Quellcode durchsuchen

微信小程序回调消息兼容json格式 (#560)

yucui xiao vor 4 Jahren
Ursprung
Commit
e952b1d55a
4 geänderte Dateien mit 89 neuen und 17 gelöschten Zeilen
  1. 1 0
      go.mod
  2. 6 0
      go.sum
  3. 27 8
      officialaccount/message/message.go
  4. 55 9
      officialaccount/server/server.go

+ 1 - 0
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
 )

+ 6 - 0
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=

+ 27 - 8
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

+ 55 - 9
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
 }