github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/core/context.go (about) 1 package core 2 3 import ( 4 "bufio" 5 "encoding/base64" 6 "encoding/xml" 7 "net/http" 8 "net/url" 9 "strconv" 10 11 "github.com/chanxuehong/wechat/internal/debug/callback" 12 "github.com/chanxuehong/wechat/internal/util" 13 ) 14 15 const ( 16 initHandlerIndex = -1 17 abortHandlerIndex = maxHandlerChainSize 18 ) 19 20 // Context 是 Handler 处理消息(事件)的上下文环境. 非并发安全! 21 type Context struct { 22 ResponseWriter http.ResponseWriter 23 Request *http.Request 24 25 QueryParams url.Values // 回调请求 URL 的查询参数集合 26 EncryptType string // 回调请求 URL 的加密方式参数: encrypt_type 27 MsgSignature string // 回调请求 URL 的消息体签名参数: msg_signature 28 Signature string // 回调请求 URL 的签名参数: signature 29 Timestamp int64 // 回调请求 URL 的时间戳参数: timestamp 30 Nonce string // 回调请求 URL 的随机数参数: nonce 31 32 MsgCiphertext []byte // 消息的密文文本 33 MsgPlaintext []byte // 消息的明文文本, xml格式 34 MixedMsg *MixedMsg // 消息 35 36 Token string // 当前消息所属公众号的 Token 37 AESKey []byte // 当前消息加密所用的 aes-key, read-only!!! 38 Random []byte // 当前消息加密所用的 random, 16-bytes 39 AppId string // 当前消息加密所用的 AppId 40 41 handlers HandlerChain 42 handlerIndex int 43 44 kvs map[string]interface{} 45 } 46 47 // IsAborted 返回 true 如果 Context.Abort() 被调用了, 否则返回 false. 48 func (ctx *Context) IsAborted() bool { 49 return ctx.handlerIndex >= abortHandlerIndex 50 } 51 52 // Abort 阻止系统调用当前 handler 后续的 handlers, 即当前的 handler 处理完毕就返回, 一般在 middleware 中调用. 53 func (ctx *Context) Abort() { 54 ctx.handlerIndex = abortHandlerIndex 55 } 56 57 // Next 中断当前 handler 程序逻辑执行其后续的 handlers, 一般在 middleware 中调用. 58 func (ctx *Context) Next() { 59 for { 60 ctx.handlerIndex++ 61 if ctx.handlerIndex >= len(ctx.handlers) { 62 ctx.handlerIndex-- 63 break 64 } 65 ctx.handlers[ctx.handlerIndex].ServeMsg(ctx) 66 } 67 } 68 69 // SetHandlers 设置 handlers 给 Context.Next() 调用, 务必在 Context.Next() 调用之前设置, 否则会 panic. 70 // 71 // NOTE: 此方法一般用不到, 除非你自己实现一个 Handler 给 Server 使用, 参考 ServeMux. 72 func (ctx *Context) SetHandlers(handlers HandlerChain) { 73 if len(handlers) > maxHandlerChainSize { 74 panic("too many handlers") 75 } 76 for _, h := range handlers { 77 if h == nil { 78 panic("handler can not be nil") 79 } 80 } 81 if ctx.handlerIndex != initHandlerIndex { 82 panic("can't set handlers after Context.Next() called") 83 } 84 ctx.handlers = handlers 85 } 86 87 // Context:kvs ========================================================================================================= 88 89 // Set 存储 key-value pair 到 Context 中. 90 func (ctx *Context) Set(key string, value interface{}) { 91 if ctx.kvs == nil { 92 ctx.kvs = make(map[string]interface{}) 93 } 94 ctx.kvs[key] = value 95 } 96 97 // Get 返回 Context 中 key 对应的 value, 如果 key 存在的返回 (value, true), 否则返回 (nil, false). 98 func (ctx *Context) Get(key string) (value interface{}, exists bool) { 99 value, exists = ctx.kvs[key] 100 return 101 } 102 103 // MustGet 返回 Context 中 key 对应的 value, 如果 key 不存在则会 panic. 104 func (ctx *Context) MustGet(key string) interface{} { 105 if value, exists := ctx.Get(key); exists { 106 return value 107 } 108 panic(`[kvs] key "` + key + `" does not exist`) 109 } 110 111 // Context:response ==================================================================================================== 112 113 // NoneResponse 表示没有消息回复给微信服务器. 114 func (ctx *Context) NoneResponse() (err error) { 115 _, err = ctx.ResponseWriter.Write(successResponseBytes) 116 return 117 } 118 119 // RawResponse 回复明文消息给微信服务器. 120 // 121 // msg: 经过 encoding/xml.Marshal 得到的结果符合微信消息格式的任何数据结构 122 func (ctx *Context) RawResponse(msg interface{}) (err error) { 123 return callback.XmlEncodeResponseMessage(ctx.ResponseWriter, msg) 124 } 125 126 // stringWriter is the interface that wraps the WriteString method. 127 type stringWriter interface { 128 WriteString(s string) (n int, err error) 129 } 130 131 // AESResponse 回复aes加密的消息给微信服务器. 132 // 133 // msg: 经过 encoding/xml.Marshal 得到的结果符合微信消息格式的任何数据结构 134 // timestamp: 时间戳, 如果为 0 则默认使用 Context.Timestamp 135 // nonce: 随机数, 如果为 "" 则默认使用 Context.Nonce 136 // random: 16字节的随机字符串, 如果为 nil 则默认使用 Context.Random 137 func (ctx *Context) AESResponse(msg interface{}, timestamp int64, nonce string, random []byte) (err error) { 138 if timestamp == 0 { 139 timestamp = ctx.Timestamp 140 } 141 if nonce == "" { 142 nonce = ctx.Nonce 143 } 144 if len(random) == 0 { 145 random = ctx.Random 146 } 147 148 msgPlaintext, err := callback.XmlMarshalResponseMessage(msg) 149 if err != nil { 150 return 151 } 152 153 encryptedMsg := util.AESEncryptMsg(random, msgPlaintext, ctx.AppId, ctx.AESKey) 154 base64EncryptedMsg := base64.StdEncoding.EncodeToString(encryptedMsg) 155 timestampString := strconv.FormatInt(timestamp, 10) 156 msgSignature := util.MsgSign(ctx.Token, timestampString, nonce, base64EncryptedMsg) 157 158 if sw, ok := ctx.ResponseWriter.(stringWriter); ok { 159 if _, err = sw.WriteString("<xml><Encrypt>"); err != nil { 160 return 161 } 162 if _, err = sw.WriteString(base64EncryptedMsg); err != nil { 163 return 164 } 165 if _, err = sw.WriteString("</Encrypt><MsgSignature>"); err != nil { 166 return 167 } 168 if _, err = sw.WriteString(msgSignature); err != nil { 169 return 170 } 171 if _, err = sw.WriteString("</MsgSignature><TimeStamp>"); err != nil { 172 return 173 } 174 if _, err = sw.WriteString(timestampString); err != nil { 175 return 176 } 177 if _, err = sw.WriteString("</TimeStamp><Nonce>"); err != nil { 178 return 179 } 180 if err = xml.EscapeText(ctx.ResponseWriter, []byte(nonce)); err != nil { 181 return 182 } 183 _, err = sw.WriteString("</Nonce></xml>") 184 return 185 } else { 186 bufw := bufio.NewWriterSize(ctx.ResponseWriter, 256) 187 if _, err = bufw.WriteString("<xml><Encrypt>"); err != nil { 188 return 189 } 190 if _, err = bufw.WriteString(base64EncryptedMsg); err != nil { 191 return 192 } 193 if _, err = bufw.WriteString("</Encrypt><MsgSignature>"); err != nil { 194 return 195 } 196 if _, err = bufw.WriteString(msgSignature); err != nil { 197 return 198 } 199 if _, err = bufw.WriteString("</MsgSignature><TimeStamp>"); err != nil { 200 return 201 } 202 if _, err = bufw.WriteString(timestampString); err != nil { 203 return 204 } 205 if _, err = bufw.WriteString("</TimeStamp><Nonce>"); err != nil { 206 return 207 } 208 if err = xml.EscapeText(bufw, []byte(nonce)); err != nil { 209 return 210 } 211 if _, err = bufw.WriteString("</Nonce></xml>"); err != nil { 212 return 213 } 214 return bufw.Flush() 215 } 216 }