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  }