1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-23 13:42:25 +08:00

Compare commits

...

5 Commits

Author SHA1 Message Date
houseme
71e348ff08 Merge 1090563e0b into 038037b89d 2023-10-16 07:17:15 +00:00
houseme
1090563e0b improve code for message 2023-10-16 15:17:03 +08:00
houseme
3d9cb16709 improve code for unmarshal message 2023-10-16 15:12:05 +08:00
houseme
fe545a6de9 improve code for message 2023-10-16 13:51:20 +08:00
houseme
5cc4af8fed improve comment 2023-10-16 13:50:37 +08:00
4 changed files with 175 additions and 53 deletions

View File

@@ -2,12 +2,12 @@ package openapi
import "github.com/silenceper/wechat/v2/util"
// GetAPIQuotaParams 查询API调用额度参数
// GetAPIQuotaParams 查询 API 调用额度参数
type GetAPIQuotaParams struct {
CgiPath string `json:"cgi_path"` // api的请求地址例如"/cgi-bin/message/custom/send";不要前缀“https://api.weixin.qq.com” ,也不要漏了"/",否则都会76003的报错
CgiPath string `json:"cgi_path"` // api 的请求地址,例如"/cgi-bin/message/custom/send";不要前缀“https://api.weixin.qq.com” ,也不要漏了"/",否则都会 76003 的报错
}
// APIQuota API调用额度
// APIQuota API 调用额度
type APIQuota struct {
util.CommonError
Quota struct {
@@ -17,20 +17,20 @@ type APIQuota struct {
} `json:"quota"` // 详情
}
// GetRidInfoParams 查询rid信息参数
// GetRidInfoParams 查询 rid 信息参数
type GetRidInfoParams struct {
Rid string `json:"rid"` // 调用接口报错返回的rid
Rid string `json:"rid"` // 调用接口报错返回的 rid
}
// RidInfo rid信息
// RidInfo rid 信息
type RidInfo struct {
util.CommonError
Request struct {
InvokeTime int64 `json:"invoke_time"` // 发起请求的时间戳
CostInMs int64 `json:"cost_in_ms"` // 请求毫秒级耗时
RequestURL string `json:"request_url"` // 请求的URL参数
RequestBody string `json:"request_body"` // post请求的请求参数
RequestURL string `json:"request_url"` // 请求的 URL 参数
RequestBody string `json:"request_body"` // post 请求的请求参数
ResponseBody string `json:"response_body"` // 接口请求返回参数
ClientIP string `json:"client_ip"` // 接口请求的客户端ip
} `json:"request"` // 该rid对应的请求详情
ClientIP string `json:"client_ip"` // 接口请求的客户端 ip
} `json:"request"` // 该 rid 对应的请求详情
}

View File

@@ -9,6 +9,8 @@ import (
"sort"
"strings"
"github.com/tidwall/gjson"
"github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/miniprogram/security"
"github.com/silenceper/wechat/v2/util"
@@ -203,32 +205,96 @@ func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, dec
return &pushData, err
case EventSubscribePopup:
// 用户操作订阅通知弹窗事件推送
var pushData PushDataSubscribePopup
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
return &pushData, err
return receiver.unmarshalSubscribePopup(dataType, decryptMsg)
case EventSubscribeMsgChange:
// 用户管理订阅通知事件推送
var pushData PushDataSubscribeMsgChange
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
return &pushData, err
return receiver.unmarshalSubscribeMsgChange(dataType, decryptMsg)
case EventSubscribeMsgSent:
// 用户发送订阅通知事件推送
var pushData PushDataSubscribeMsgSent
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
return &pushData, err
return receiver.unmarshalSubscribeMsgSent(dataType, decryptMsg)
}
// 暂不支持其他事件类型,直接返回解密后的数据,由调用方处理
return decryptMsg, nil
}
// unmarshal 解析推送的数据
func (receiver *PushReceiver) unmarshal(dateType string, decryptMsg []byte, pushData interface{}) error {
if dateType == DataTypeXML {
func (receiver *PushReceiver) unmarshal(dataType string, decryptMsg []byte, pushData interface{}) error {
if dataType == DataTypeXML {
return xml.Unmarshal(decryptMsg, pushData)
}
return json.Unmarshal(decryptMsg, pushData)
}
// unmarshalSubscribePopup
func (receiver *PushReceiver) unmarshalSubscribePopup(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribePopup
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgPopupEventList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgPopupEvents([]SubscribeMsgPopupEventList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgPopupEventList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgPopupEvents(listItems)
}
}
return &pushData, err
}
// unmarshalSubscribeMsgChange 解析用户管理订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgChange(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribeMsgChange
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgChangeList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgChangeEvents([]SubscribeMsgChangeList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgChangeList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgChangeEvents(listItems)
}
}
return &pushData, err
}
// unmarshalSubscribeMsgSent 解析用户发送订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgSent(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribeMsgSent
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgSentList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgSentEvents([]SubscribeMsgSentList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgSentList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgSentEvents(listItems)
}
}
return &pushData, err
}
// DataReceived 接收到的数据
type DataReceived struct {
Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
@@ -405,12 +471,13 @@ type CoinInfo struct {
// PushDataSubscribePopup 用户操作订阅通知弹窗事件推送
type PushDataSubscribePopup struct {
CommonPushData
List []SubscribeMsgPopupEventList `xml:"SubscribeMsgPopupEvent>List" json:"List"`
subscribeMsgPopupEventList []SubscribeMsgPopupEventList `json:"-"`
SubscribeMsgPopupEvent SubscribeMsgPopupEvent `xml:"SubscribeMsgPopupEvent"`
}
// SubscribeMsgPopupEvent 用户操作订阅通知弹窗消息回调
type SubscribeMsgPopupEvent struct {
List []SubscribeMsgPopupEventList `xml:"List" json:"List"`
List []SubscribeMsgPopupEventList `xml:"List"`
}
// SubscribeMsgPopupEventList 订阅消息事件列表
@@ -420,10 +487,28 @@ type SubscribeMsgPopupEventList struct {
PopupScene string `xml:"PopupScene" json:"PopupScene"`
}
// SetSubscribeMsgPopupEvents 设置订阅消息事件
func (s *PushDataSubscribePopup) SetSubscribeMsgPopupEvents(list []SubscribeMsgPopupEventList) {
s.subscribeMsgPopupEventList = list
}
// GetSubscribeMsgPopupEvents 获取订阅消息事件数据
func (s *PushDataSubscribePopup) GetSubscribeMsgPopupEvents() []SubscribeMsgPopupEventList {
if s.subscribeMsgPopupEventList != nil {
return s.subscribeMsgPopupEventList
}
if s.SubscribeMsgPopupEvent.List == nil || len(s.SubscribeMsgPopupEvent.List) < 1 {
return nil
}
return s.SubscribeMsgPopupEvent.List
}
// PushDataSubscribeMsgChange 用户管理订阅通知事件推送
type PushDataSubscribeMsgChange struct {
CommonPushData
List []SubscribeMsgChangeList `xml:"SubscribeMsgChangeEvent>List" json:"List"`
SubscribeMsgChangeEvent SubscribeMsgChangeEvent `xml:"SubscribeMsgChangeEvent"`
subscribeMsgChangeList []SubscribeMsgChangeList `json:"-"`
}
// SubscribeMsgChangeEvent 用户管理订阅通知回调
@@ -437,21 +522,58 @@ type SubscribeMsgChangeList struct {
SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
}
// SetSubscribeMsgChangeEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgChange) SetSubscribeMsgChangeEvents(list []SubscribeMsgChangeList) {
s.subscribeMsgChangeList = list
}
// GetSubscribeMsgChangeEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgChange) GetSubscribeMsgChangeEvents() []SubscribeMsgChangeList {
if s.subscribeMsgChangeList != nil {
return s.subscribeMsgChangeList
}
if s.SubscribeMsgChangeEvent.List == nil || len(s.SubscribeMsgChangeEvent.List) < 1 {
return nil
}
return s.SubscribeMsgChangeEvent.List
}
// PushDataSubscribeMsgSent 用户发送订阅通知事件推送
type PushDataSubscribeMsgSent struct {
CommonPushData
List []SubscribeMsgSentEventList `xml:"SubscribeMsgSentEvent>List" json:"List"`
SubscribeMsgSentEvent SubscribeMsgSentEvent `xml:"SubscribeMsgSentEvent"`
subscribeMsgSentEventList []SubscribeMsgSentList `json:"-"`
}
// SubscribeMsgSentEvent 用户发送订阅通知回调
type SubscribeMsgSentEvent struct {
List []SubscribeMsgSentEventList `xml:"List" json:"List"`
List []SubscribeMsgSentList `xml:"List" json:"List"`
}
// SubscribeMsgSentEventList 订阅消息事件列表
type SubscribeMsgSentEventList struct {
// SubscribeMsgSentList 订阅消息事件列表
type SubscribeMsgSentList struct {
TemplateID string `xml:"TemplateId" json:"TemplateId"`
MsgID string `xml:"MsgID" json:"MsgID"`
ErrorCode int `xml:"ErrorCode" json:"ErrorCode"`
ErrorStatus string `xml:"ErrorStatus" json:"ErrorStatus"`
}
// SetSubscribeMsgSentEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgSent) SetSubscribeMsgSentEvents(list []SubscribeMsgSentList) {
s.subscribeMsgSentEventList = list
}
// GetSubscribeMsgSentEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgSent) GetSubscribeMsgSentEvents() []SubscribeMsgSentList {
if s.subscribeMsgSentEventList != nil {
return s.subscribeMsgSentEventList
}
if s.SubscribeMsgSentEvent.List == nil || len(s.SubscribeMsgSentEvent.List) < 1 {
return nil
}
return s.SubscribeMsgSentEvent.List
}

View File

@@ -27,15 +27,15 @@ const (
MsgTypeVideo MsgType = "video"
// MsgTypeMiniprogrampage 表示小程序卡片消息
MsgTypeMiniprogrampage MsgType = "miniprogrampage"
// MsgTypeShortVideo 表示短视频消息[限接收]
// MsgTypeShortVideo 表示短视频消息 [限接收]
MsgTypeShortVideo MsgType = "shortvideo"
// MsgTypeLocation 表示坐标消息[限接收]
// MsgTypeLocation 表示坐标消息 [限接收]
MsgTypeLocation MsgType = "location"
// MsgTypeLink 表示链接消息[限接收]
// MsgTypeLink 表示链接消息 [限接收]
MsgTypeLink MsgType = "link"
// MsgTypeMusic 表示音乐消息[限回复]
// MsgTypeMusic 表示音乐消息 [限回复]
MsgTypeMusic MsgType = "music"
// MsgTypeNews 表示图文消息[限回复]
// MsgTypeNews 表示图文消息 [限回复]
MsgTypeNews MsgType = "news"
// MsgTypeTransfer 表示消息消息转发到客服
MsgTypeTransfer MsgType = "transfer_customer_service"
@@ -91,7 +91,7 @@ const (
const (
// 微信开放平台需要用到
// InfoTypeVerifyTicket 返回ticket
// InfoTypeVerifyTicket 返回 ticket
InfoTypeVerifyTicket InfoType = "component_verify_ticket"
// InfoTypeAuthorized 授权
InfoTypeAuthorized InfoType = "authorized"
@@ -108,8 +108,8 @@ type MixMessage struct {
CommonToken
// 基本消息
MsgID int64 `xml:"MsgId"` // 其他消息推送过来是MsgId
TemplateMsgID int64 `xml:"MsgID"` // 模板消息推送成功的消息是MsgID
MsgID int64 `xml:"MsgId"` // 其他消息推送过来是 MsgId
TemplateMsgID int64 `xml:"MsgID"` // 模板消息推送成功的消息是 MsgID
Content string `xml:"Content"`
Recognition string `xml:"Recognition"`
PicURL string `xml:"PicUrl"`
@@ -166,17 +166,17 @@ type MixMessage struct {
// 事件相关:发布能力
PublishEventInfo struct {
PublishID int64 `xml:"publish_id"` // 发布任务id
PublishID int64 `xml:"publish_id"` // 发布任务 id
PublishStatus freepublish.PublishStatus `xml:"publish_status"` // 发布状态
ArticleID string `xml:"article_id"` // 当发布状态为0时(即成功)时,返回图文的 article_id可用于“客服消息”场景
ArticleID string `xml:"article_id"` // 当发布状态为 0 时(即成功)时,返回图文的 article_id可用于“客服消息”场景
ArticleDetail struct {
Count uint `xml:"count"` // 文章数量
Item []struct {
Index uint `xml:"idx"` // 文章对应的编号
ArticleURL string `xml:"article_url"` // 图文的永久链接
} `xml:"item"`
} `xml:"article_detail"` // 当发布状态为0时(即成功)时,返回内容
FailIndex []uint `xml:"fail_idx"` // 当发布状态为2或4时,返回不通过的文章编号,第一篇为 1其他发布状态则为空
} `xml:"article_detail"` // 当发布状态为 0 时(即成功)时,返回内容
FailIndex []uint `xml:"fail_idx"` // 当发布状态为 2 或 4 时,返回不通过的文章编号,第一篇为 1其他发布状态则为空
} `xml:"PublishEventInfo"`
// 第三方平台相关
@@ -222,19 +222,19 @@ type MixMessage struct {
TraceID string `xml:"trace_id"`
StatusCode int `xml:"status_code"`
//小程序名称审核结果事件推送
Ret int32 `xml:"ret"` //审核结果 2失败3成功
NickName string `xml:"nickname"` //小程序昵称
// 小程序名称审核结果事件推送
Ret int32 `xml:"ret"` // 审核结果 2失败3成功
NickName string `xml:"nickname"` // 小程序昵称
// 设备相关
device.MsgDevice
//小程序审核通知
SuccTime int `xml:"SuccTime"` //审核成功时的时间戳
FailTime int `xml:"FailTime"` //审核不通过的时间戳
DelayTime int `xml:"DelayTime"` //审核延后时的时间戳
Reason string `xml:"Reason"` //审核不通过的原因
ScreenShot string `xml:"ScreenShot"` //审核不通过的截图示例。用 | 分隔的 media_id 的列表,可通过获取永久素材接口拉取截图内容
// 小程序审核通知
SuccTime int `xml:"SuccTime"` // 审核成功时的时间戳
FailTime int `xml:"FailTime"` // 审核不通过的时间戳
DelayTime int `xml:"DelayTime"` // 审核延后时的时间戳
Reason string `xml:"Reason"` // 审核不通过的原因
ScreenShot string `xml:"ScreenShot"` // 审核不通过的截图示例。用 | 分隔的 media_id 的列表,可通过获取永久素材接口拉取截图内容
}
// SubscribeMsgPopupEvent 订阅通知事件推送的消息体
@@ -282,7 +282,7 @@ type ResponseEncryptedXMLMsg struct {
Nonce string `xml:"Nonce" json:"Nonce"`
}
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略
// CDATA 使用该类型在序列化为 xml 文本时文本会被解析器忽略
type CDATA string
// MarshalXML 实现自己的序列化方法

View File

@@ -73,7 +73,7 @@ func (srv *Server) Serve() error {
if err != nil {
return err
}
// 非安全模式下请求处理方法返回为nil则直接回复success给微信服务器
// 非安全模式下,请求处理方法返回为 nil 则直接回复 success 给微信服务器
if response == nil && !srv.isSafeMode {
srv.String("success")
return nil
@@ -198,7 +198,7 @@ func (srv *Server) parseRequestMessage(rawXMLMsgBytes []byte) (msg *message.MixM
if err != nil {
return
}
// nonstandard json, 目前小程序订阅消息返回数据格式不标准订阅消息模板单个List返回是对象多个List返回是数组。
// nonstandard json, 目前小程序订阅消息返回数据格式不标准,订阅消息模板单个 List 返回是对象,多个 List 返回是数组。
if msg.MsgType == message.MsgTypeEvent {
listData := gjson.Get(string(rawXMLMsgBytes), "List")
if listData.IsObject() {
@@ -284,7 +284,7 @@ func (srv *Server) Send() (err error) {
if err != nil {
return
}
// TODO 如果获取不到timestamp nonce 则自己生成
// TODO 如果获取不到 timestamp nonce 则自己生成
timestamp := srv.timestamp
timestampStr := strconv.FormatInt(timestamp, 10)
msgSignature := util.Signature(srv.Token, timestampStr, srv.nonce, string(encryptedMsg))