diff --git a/go.mod b/go.mod index 24f8bf1..b22b780 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cast v1.4.1 github.com/stretchr/testify v1.7.1 + github.com/tidwall/gjson v1.14.1 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 gopkg.in/h2non/gock.v1 v1.1.2 ) diff --git a/go.sum b/go.sum index 5d577c2..41e1c54 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,12 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index 841f22f..023d59d 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -117,7 +117,7 @@ type MixMessage struct { URL string `xml:"Url"` // 事件相关 - Event EventType `xml:"Event"` + Event EventType `xml:"Event" json:"Event"` EventKey string `xml:"EventKey"` Ticket string `xml:"Ticket"` Latitude string `xml:"Latitude"` @@ -149,6 +149,8 @@ type MixMessage struct { Poiname string `xml:"Poiname"` } + subscribeMsgPopupEventList []SubscribeMsgPopupEvent `json:"-"` + SubscribeMsgPopupEvent []struct { List SubscribeMsgPopupEvent `xml:"List"` } `xml:"SubscribeMsgPopupEvent"` @@ -209,9 +211,26 @@ type MixMessage struct { // SubscribeMsgPopupEvent 订阅通知事件推送的消息体 type SubscribeMsgPopupEvent struct { - TemplateID string `xml:"TemplateId"` - SubscribeStatusString string `xml:"SubscribeStatusString"` - PopupScene int `xml:"PopupScene"` + TemplateID string `xml:"TemplateId" json:"TemplateId"` + SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"` + PopupScene int `xml:"PopupScene" json:"PopupScene,string"` +} + +// SetSubscribeMsgPopupEvents 设置订阅消息事件 +func (s *MixMessage) SetSubscribeMsgPopupEvents(list []SubscribeMsgPopupEvent) { + s.subscribeMsgPopupEventList = list +} + +// GetSubscribeMsgPopupEvents 获取订阅消息事件数据 +func (s *MixMessage) GetSubscribeMsgPopupEvents() []SubscribeMsgPopupEvent { + if s.subscribeMsgPopupEventList != nil { + return s.subscribeMsgPopupEventList + } + list := make([]SubscribeMsgPopupEvent, len(s.SubscribeMsgPopupEvent)) + for i, item := range s.SubscribeMsgPopupEvent { + list[i] = item.List + } + return list } // EventPic 发图事件推送 @@ -248,10 +267,10 @@ func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error { // CommonToken 消息中通用的结构 type CommonToken struct { XMLName xml.Name `xml:"xml"` - ToUserName CDATA `xml:"ToUserName"` - FromUserName CDATA `xml:"FromUserName"` - CreateTime int64 `xml:"CreateTime"` - MsgType MsgType `xml:"MsgType"` + ToUserName CDATA `xml:"ToUserName" json:"ToUserName"` + FromUserName CDATA `xml:"FromUserName" json:"FromUserName"` + CreateTime int64 `xml:"CreateTime" json:"CreateTime"` + MsgType MsgType `xml:"MsgType" json:"MsgType"` } // SetToUserName set ToUserName diff --git a/officialaccount/server/server.go b/officialaccount/server/server.go index 955d250..c6f6812 100644 --- a/officialaccount/server/server.go +++ b/officialaccount/server/server.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "encoding/xml" "errors" "fmt" @@ -9,13 +10,14 @@ import ( "reflect" "runtime/debug" "strconv" + "strings" log "github.com/sirupsen/logrus" "github.com/silenceper/wechat/v2/officialaccount/context" "github.com/silenceper/wechat/v2/officialaccount/message" - "github.com/silenceper/wechat/v2/util" + "github.com/tidwall/gjson" ) // Server struct @@ -35,10 +37,11 @@ type Server struct { ResponseRawXMLMsg []byte ResponseMsg interface{} - isSafeMode bool - random []byte - nonce string - timestamp int64 + isSafeMode bool + isJSONContent bool + random []byte + nonce string + timestamp int64 } // NewServer init @@ -98,6 +101,10 @@ func (srv *Server) handleRequest() (reply *message.Reply, err error) { srv.isSafeMode = true } + //set request contentType + contentType := srv.Request.Header.Get("Content-Type") + srv.isJSONContent = strings.Contains(contentType, "application/json") + // set openID srv.openID = srv.Query("openid") @@ -125,9 +132,9 @@ func (srv *Server) getMessage() (interface{}, error) { var rawXMLMsgBytes []byte var err error if srv.isSafeMode { - var encryptedXMLMsg message.EncryptedXMLMsg - if err := xml.NewDecoder(srv.Request.Body).Decode(&encryptedXMLMsg); err != nil { - return nil, fmt.Errorf("从body中解析xml失败,err=%v", err) + encryptedXMLMsg, dataErr := srv.getEncryptBody() + if dataErr != nil { + return nil, dataErr } // 验证消息签名 @@ -161,9 +168,48 @@ func (srv *Server) getMessage() (interface{}, error) { return srv.parseRequestMessage(rawXMLMsgBytes) } +func (srv *Server) getEncryptBody() (*message.EncryptedXMLMsg, error) { + var encryptedXMLMsg = &message.EncryptedXMLMsg{} + if srv.isJSONContent { + if err := json.NewDecoder(srv.Request.Body).Decode(encryptedXMLMsg); err != nil { + return nil, fmt.Errorf("从body中解析json失败,err=%v", err) + } + } else { + if err := xml.NewDecoder(srv.Request.Body).Decode(encryptedXMLMsg); err != nil { + return nil, fmt.Errorf("从body中解析xml失败,err=%v", err) + } + } + return encryptedXMLMsg, nil +} + func (srv *Server) parseRequestMessage(rawXMLMsgBytes []byte) (msg *message.MixMessage, err error) { msg = &message.MixMessage{} - err = xml.Unmarshal(rawXMLMsgBytes, msg) + if !srv.isJSONContent { + err = xml.Unmarshal(rawXMLMsgBytes, msg) + return + } + //parse json + err = json.Unmarshal(rawXMLMsgBytes, msg) + if err != nil { + return + } + // nonstandard json, 目前小程序订阅消息返回数据格式不标准,订阅消息模板单个List返回是对象,多个List返回是数组。 + if msg.MsgType == message.MsgTypeEvent { + listData := gjson.Get(string(rawXMLMsgBytes), "List") + if listData.IsObject() { + listItem := message.SubscribeMsgPopupEvent{} + if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil { + return msg, parseErr + } + msg.SetSubscribeMsgPopupEvents([]message.SubscribeMsgPopupEvent{listItem}) + } else if listData.IsArray() { + listItems := make([]message.SubscribeMsgPopupEvent, 0) + if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil { + return msg, parseErr + } + msg.SetSubscribeMsgPopupEvents(listItems) + } + } return }