mp

package
Version: v0.0.0-...-5652a87 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 18, 2017 License: Apache-2.0 Imports: 18 Imported by: 0

README

微信公众平台(订阅号、服务号) golang SDK

整体架构图

架构图

示例

主動調用微信 api,mp 子包裏面的 Client 基本都是這樣的調用方式
package main

import (
	"fmt"

	"github.com/chanxuehong/wechat/mp"
	"github.com/chanxuehong/wechat/mp/menu"
)

var AccessTokenServer = mp.NewDefaultAccessTokenServer("appId", "appSecret", nil) // 一個應用只能有一個實例
var mpClient = mp.NewClient(AccessTokenServer, nil)

func main() {
	var subButtons = make([]menu.Button, 2)
	subButtons[0].SetAsViewButton("搜索", "http://www.soso.com/")
	subButtons[1].SetAsClickButton("赞一下我们", "V1001_GOOD")

	var mn menu.Menu
	mn.Buttons = make([]menu.Button, 3)
	mn.Buttons[0].SetAsClickButton("今日歌曲", "V1001_TODAY_MUSIC")
	mn.Buttons[1].SetAsViewButton("视频", "http://v.qq.com/")
	mn.Buttons[2].SetAsSubMenuButton("子菜单", subButtons)

	menuClient := (*menu.Client)(mpClient)
	if err := menuClient.CreateMenu(mn); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("ok")
}
被動接收消息(事件)推送,一个 URL 监听一个公众号的消息
package main

import (
	"log"
	"net/http"

	"github.com/chanxuehong/wechat/mp"
	"github.com/chanxuehong/wechat/mp/message/request"
	"github.com/chanxuehong/wechat/mp/message/response"
	"github.com/chanxuehong/wechat/util"
)

func ErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
	log.Println(err.Error())
}

// 文本消息的 Handler
func TextMessageHandler(w http.ResponseWriter, r *mp.Request) {
	// 简单起见,把用户发送过来的文本原样回复过去
	text := request.GetText(r.MixedMsg) // 可以省略, 直接从 r.MixedMsg 取值
	resp := response.NewText(text.FromUserName, text.ToUserName, text.CreateTime, text.Content)
	//mp.WriteRawResponse(w, r, resp) // 明文模式
	mp.WriteAESResponse(w, r, resp) // 安全模式
}

func main() {
	aesKey, err := util.AESKeyDecode("encodedAESKey") // 这里 encodedAESKey 改成你自己的参数
	if err != nil {
		panic(err)
	}

	messageServeMux := mp.NewMessageServeMux()
	messageServeMux.MessageHandleFunc(request.MsgTypeText, TextMessageHandler) // 注册文本处理 Handler

	// 下面函数的几个参数设置成你自己的参数: oriId, token, appId
	mpServer := mp.NewDefaultServer("oriId", "token", "appId", aesKey, messageServeMux)

	mpServerFrontend := mp.NewServerFrontend(mpServer, mp.ErrorHandlerFunc(ErrorHandler), nil)

	// 如果你在微信后台设置的回调地址是
	//   http://xxx.yyy.zzz/wechat
	// 那么可以这么注册 http.Handler
	http.Handle("/wechat", mpServerFrontend)
	http.ListenAndServe(":80", nil)
}
被動接收消息(事件)推送,一个 URL 监听多个公众号的消息
package main

import (
	"log"
	"net/http"

	"github.com/chanxuehong/wechat/mp"
	"github.com/chanxuehong/wechat/mp/message/request"
	"github.com/chanxuehong/wechat/mp/message/response"
	"github.com/chanxuehong/wechat/util"
)

func ErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
	log.Println(err.Error())
}

// 文本消息的 Handler
func TextMessageHandler(w http.ResponseWriter, r *mp.Request) {
	// 简单起见,把用户发送过来的文本原样回复过去
	text := request.GetText(r.MixedMsg) // 可以省略, 直接从 r.MixedMsg 取值
	resp := response.NewText(text.FromUserName, text.ToUserName, text.CreateTime, text.Content)
	//mp.WriteRawResponse(w, r, resp) // 明文模式
	mp.WriteAESResponse(w, r, resp) // 安全模式
}

func main() {
	// mpServer1
	aesKey1, err := util.AESKeyDecode("encodedAESKey1") // 这里 encodedAESKey1 改成你自己的参数
	if err != nil {
		panic(err)
	}

	messageServeMux1 := mp.NewMessageServeMux()
	messageServeMux1.MessageHandleFunc(request.MsgTypeText, TextMessageHandler) // 注册文本处理 Handler

	// 下面函数的几个参数设置成你自己的参数: oriId1, token1, appId1
	mpServer1 := mp.NewDefaultServer("oriId1", "token1", "appId1", aesKey1, messageServeMux1)

	// mpServer2
	aesKey2, err := util.AESKeyDecode("encodedAESKey2") // 这里 encodedAESKey2 改成你自己的参数
	if err != nil {
		panic(err)
	}

	messageServeMux2 := mp.NewMessageServeMux()
	messageServeMux2.MessageHandleFunc(request.MsgTypeText, TextMessageHandler) // 注册文本处理 Handler

	// 下面函数的几个参数设置成你自己的参数: oriId2, token2, appId2
	mpServer2 := mp.NewDefaultServer("oriId2", "token2", "appId2", aesKey2, messageServeMux2)

	// multiServerFrontend, 第一个参数可以不是 wechat_server, 可以自己指定
	multiServerFrontend := mp.NewMultiServerFrontend("wechat_server", mp.ErrorHandlerFunc(ErrorHandler), nil)
	multiServerFrontend.SetServer("wechat1", mpServer1) // 回調url上面要加上 wechat_server=wechat1
	multiServerFrontend.SetServer("wechat2", mpServer2) // 回調url上面要加上 wechat_server=wechat2

	// 如果你在微信后台设置的回调地址是
	//   http://xxx.yyy.zzz/wechat
	// 那么可以这么注册 http.Handler
	http.Handle("/wechat", multiServerFrontend)
	http.ListenAndServe(":80", nil)
}

Documentation

Overview

微信公众平台(订阅号, 服务号)SDK

Index

Constants

View Source
const (
	ErrCodeOK                 = 0
	ErrCodeInvalidCredential  = 40001 // access_token 过期(无效)返回这个错误
	ErrCodeAccessTokenExpired = 42001 // access_token 过期(无效)返回这个错误(maybe!!!)
)

Variables

View Source
var DefaultErrorHandler = ErrorHandlerFunc(func(w http.ResponseWriter, r *http.Request, err error) {})
View Source
var LogInfoln = log.Println
View Source
var MediaHttpClient = &http.Client{
	Timeout: 300 * time.Second,
}

多媒体上传下载请求的 http.Client

View Source
var TextHttpClient = &http.Client{
	Timeout: 60 * time.Second,
}

一般请求的 http.Client

Functions

func ServeHTTP

func ServeHTTP(w http.ResponseWriter, r *http.Request, queryValues url.Values, srv Server, errHandler ErrorHandler)

ServeHTTP 处理 http 消息请求

NOTE: 调用者保证所有参数有效

func SetLogInfoln

func SetLogInfoln(fn func(v ...interface{}))

沒有加锁, 请确保在初始化阶段调用!

func WriteAESResponse

func WriteAESResponse(w http.ResponseWriter, r *Request, msg interface{}) (err error)

安全模式下回复消息给微信服务器.

要求 msg 是有效的消息数据结构(经过 encoding/xml marshal 后符合微信消息格式);
如果有必要可以修改 Request 里面的某些值, 比如 Timestamp, Nonce, Random.

func WriteRawResponse

func WriteRawResponse(w http.ResponseWriter, r *Request, msg interface{}) (err error)

明文模式下回复消息给微信服务器.

要求 msg 是有效的消息数据结构(经过 encoding/xml marshal 后符合微信消息格式);
如果有必要可以修改 Request 里面的某些值, 比如 Timestamp, Nonce, Random.

Types

type AccessTokenServer

type AccessTokenServer interface {
	// 从中控服务器获取被缓存的 access_token.
	Token() (string, error)

	// 请求中控服务器到微信服务器刷新 access_token.
	//
	//  高并发场景下某个时间点可能有很多请求(比如缓存的 access_token 刚好过期时), 但是我们
	//  不期望也没有必要让这些请求都去微信服务器获取 access_token(有可能导致api超过调用限制),
	//  实际上这些请求只需要一个新的 access_token 即可, 所以建议 AccessTokenServer 从微信服务器
	//  获取一次 access_token 之后的至多5秒内(收敛时间, 视情况而定, 理论上至多5个http或tcp周期)
	//  再次调用该函数不再去微信服务器获取, 而是直接返回之前的结果.
	TokenRefresh() (string, error)

	// 没有实际意义, 接口标识
	TagCE90001AFE9C11E48611A4DB30FED8E1()
}

access_token 中控服务器接口, see access_token_server.png

type AddFriendAutoReplyInfo

type AddFriendAutoReplyInfo struct {
	Type    string `json:"type"`    // 自动回复的类型。关注后自动回复和消息自动回复的类型仅支持文本(text)、图片(img)、语音(voice)、视频(video),关键词自动回复则还多了图文消息
	Content string `json:"content"` // 对于文本类型,content是文本内容,对于图片、语音、视频类型,content是mediaID
}

关注后自动回复的信息

type AroundBeacon

type AroundBeacon struct {
	UUID     string  `xml:"Uuid"     json:"Uuid"`
	Major    int     `xml:"Major"    json:"Major"`
	Minor    int     `xml:"Minor"    json:"Minor"`
	Distance float64 `xml:"Distance" json:"Distance"`
}

和 github.com/chanxuehong/wechat/mp/shakearound.AroundBeacon 一样, 同步修改

type Article

type Article struct {
	Title      string `json:"title"`       // 图文消息的标题
	Author     string `json:"author"`      // 作者
	Digest     string `json:"digest"`      // 摘要
	ShowCover  int    `json:"show_cover"`  // 是否显示封面,0为不显示,1为显示
	CoverURL   string `json:"cover_url"`   // 封面图片的URL
	ContentURL string `json:"content_url"` // 正文的URL
	SourceURL  string `json:"source_url"`  // 原文的URL,若置空则无查看原文入口
}

type AutoReplyInfo

type AutoReplyInfo struct {
	IsAddFriendReplyOpen int `json:"is_add_friend_reply_open"` // 关注后自动回复是否开启,0代表未开启,1代表开启
	IsAutoReplyOpen      int `json:"is_autoreply_open"`        // 消息自动回复是否开启,0代表未开启,1代表开启

	AddFriendAutoReplyInfo      *AddFriendAutoReplyInfo      `json:"add_friend_autoreply_info,omitempty"`      // 关注后自动回复的信息
	MessageDefaultAutoReplyInfo *MessageDefaultAutoReplyInfo `json:"message_default_autoreply_info,omitempty"` // 消息自动回复的信息
	KeywordAutoReplyInfo        *KeywordAutoReplyInfo        `json:"keyword_autoreply_info,omitempty"`         // 关键词自动回复的信息
}

type ChosenBeacon

type ChosenBeacon struct {
	UUID     string  `xml:"Uuid"     json:"Uuid"`
	Major    int     `xml:"Major"    json:"Major"`
	Minor    int     `xml:"Minor"    json:"Minor"`
	Distance float64 `xml:"Distance" json:"Distance"`
}

和 github.com/chanxuehong/wechat/mp/shakearound.ChosenBeacon 一样, 同步修改

type Client

type Client struct {
	AccessTokenServer
	HttpClient *http.Client
}

func NewClient

func NewClient(srv AccessTokenServer, clt *http.Client) *Client

创建一个新的 Client.

如果 clt == nil 则默认用 http.DefaultClient

func (*Client) GetAutoReplyInfo

func (clt *Client) GetAutoReplyInfo() (info *AutoReplyInfo, err error)

获取自动回复规则

func (*Client) GetCallbackIP

func (clt *Client) GetCallbackIP() (ipList []string, err error)

获取微信服务器IP地址.

如果公众号基于安全等考虑, 需要获知微信服务器的IP地址列表, 以便进行相关限制,
可以通过该接口获得微信服务器IP地址列表.

func (*Client) GetJSON

func (clt *Client) GetJSON(incompleteURL string, response interface{}) (err error)

GET 微信资源, 然后将微信服务器返回的 JSON 用 encoding/json 解析到 response.

NOTE:
1. 一般不用调用这个方法, 请直接调用高层次的封装方法;
2. 最终的 URL == incompleteURL + access_token;
3. response 格式有要求, 要么是 *Error, 要么是下面结构体的指针(注意 Error 必须是第一个 Field):
    struct {
        Error
        ...
    }

func (*Client) PostJSON

func (clt *Client) PostJSON(incompleteURL string, request interface{}, response interface{}) (err error)

用 encoding/json 把 request marshal 为 JSON, 放入 http 请求的 body 中, POST 到微信服务器, 然后将微信服务器返回的 JSON 用 encoding/json 解析到 response.

NOTE:
1. 一般不用调用这个方法, 请直接调用高层次的封装方法;
2. 最终的 URL == incompleteURL + access_token;
3. response 格式有要求, 要么是 *Error, 要么是下面结构体的指针(注意 Error 必须是第一个 Field):
    struct {
        Error
        ...
    }

func (*Client) PostMultipartForm

func (clt *Client) PostMultipartForm(incompleteURL string, fields []MultipartFormField, response interface{}) (err error)

通用上传接口.

--BOUNDARY
Content-Disposition: form-data; name="FIELDNAME"; filename="FILENAME"
Content-Type: application/octet-stream

FILE-CONTENT
--BOUNDARY
Content-Disposition: form-data; name="FIELDNAME"

JSON-DESCRIPTION
--BOUNDARY--

NOTE:
1. 一般不需要调用这个方法, 请直接调用高层次的封装方法;
2. 最终的 URL == incompleteURL + access_token;
3. response 格式有要求, 要么是 *Error, 要么是下面结构体的指针(注意 Error 必须是第一个 Field):
    struct {
        Error
        ...
    }

type DefaultAccessTokenServer

type DefaultAccessTokenServer struct {
	// contains filtered or unexported fields
}

AccessTokenServer 的简单实现.

NOTE:
1. 用于单进程环境.
2. 因为 DefaultAccessTokenServer 同时也是一个简单的中控服务器, 而不是仅仅实现 AccessTokenServer 接口,
   所以整个系统只能存在一个 DefaultAccessTokenServer 实例!

func NewDefaultAccessTokenServer

func NewDefaultAccessTokenServer(appId, appSecret string, clt *http.Client) (srv *DefaultAccessTokenServer)

创建一个新的 DefaultAccessTokenServer.

如果 clt == nil 则默认使用 http.DefaultClient.

func (*DefaultAccessTokenServer) TagCE90001AFE9C11E48611A4DB30FED8E1

func (srv *DefaultAccessTokenServer) TagCE90001AFE9C11E48611A4DB30FED8E1()

func (*DefaultAccessTokenServer) Token

func (srv *DefaultAccessTokenServer) Token() (token string, err error)

func (*DefaultAccessTokenServer) TokenRefresh

func (srv *DefaultAccessTokenServer) TokenRefresh() (token string, err error)

type DefaultServer

type DefaultServer struct {
	// contains filtered or unexported fields
}

func NewDefaultServer

func NewDefaultServer(oriId, token, appId string, aesKey []byte, handler MessageHandler) (srv *DefaultServer)

NewDefaultServer 创建一个新的 DefaultServer.

如果是明文模式, 则 appId 可以为 "", aesKey 可以为 nil.

func (*DefaultServer) AppId

func (srv *DefaultServer) AppId() string

func (*DefaultServer) CurrentAESKey

func (srv *DefaultServer) CurrentAESKey() (key [32]byte)

func (*DefaultServer) LastAESKey

func (srv *DefaultServer) LastAESKey() (key [32]byte, valid bool)

func (*DefaultServer) MessageHandler

func (srv *DefaultServer) MessageHandler() MessageHandler

func (*DefaultServer) OriId

func (srv *DefaultServer) OriId() string

func (*DefaultServer) Token

func (srv *DefaultServer) Token() string

func (*DefaultServer) UpdateAESKey

func (srv *DefaultServer) UpdateAESKey(aesKey []byte) (err error)

type Error

type Error struct {
	// NOTE: StructField 固定这个顺序, RETRY 依赖这个顺序
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
}

func (*Error) Error

func (e *Error) Error() string

type ErrorHandler

type ErrorHandler interface {
	ServeError(http.ResponseWriter, *http.Request, error)
}

type ErrorHandlerFunc

type ErrorHandlerFunc func(http.ResponseWriter, *http.Request, error)

func (ErrorHandlerFunc) ServeError

func (fn ErrorHandlerFunc) ServeError(w http.ResponseWriter, r *http.Request, err error)

type Interceptor

type Interceptor interface {
	// 拦截 http 请求, 根据需要做一些判断, 返回是否允许后续逻辑继续处理请求, 如返回 false 则表示请求到此为止.
	// 请注意, 后续逻辑需要读取 r.Body 里的内容, 请谨慎读取!
	Intercept(w http.ResponseWriter, r *http.Request, queryValues url.Values) (shouldContinue bool)
}

http 请求拦截器

type InterceptorFunc

type InterceptorFunc func(w http.ResponseWriter, r *http.Request, queryValues url.Values) (shouldContinue bool)

func (InterceptorFunc) Intercept

func (fn InterceptorFunc) Intercept(w http.ResponseWriter, r *http.Request, queryValues url.Values) (shouldContinue bool)

type KeywordAutoReplyInfo

type KeywordAutoReplyInfo struct {
	RuleList []KeywordAutoReplyRule `json:"list,omitempty"`
}

关键词自动回复的信息

type KeywordAutoReplyRule

type KeywordAutoReplyRule struct {
	RuleName        string        `json:"rule_name"`                   // 规则名称
	CreateTime      int64         `json:"create_time"`                 // 创建时间
	ReplyMode       string        `json:"reply_mode"`                  // 回复模式,reply_all代表全部回复,random_one代表随机回复其中一条
	KeywordInfoList []KeywordInfo `json:"keyword_list_info,omitempty"` // 匹配的关键词列表
	ReplyInfoList   []ReplyInfo   `json:"reply_list_info,omitempty"`   // 回复信息列表
}

关键词自动回复的规则

type KeywordInfo

type KeywordInfo struct {
	Type      string `json:"type"` // 一般都是文本吧???
	Content   string `json:"content"`
	MatchMode string `json:"match_mode"` // 匹配模式,contain代表消息中含有该关键词即可,equal表示消息内容必须和关键词严格相同
}

关键词匹配规则

type MessageDefaultAutoReplyInfo

type MessageDefaultAutoReplyInfo struct {
	Type    string `json:"type"`    // 自动回复的类型。关注后自动回复和消息自动回复的类型仅支持文本(text)、图片(img)、语音(voice)、视频(video),关键词自动回复则还多了图文消息
	Content string `json:"content"` // 对于文本类型,content是文本内容,对于图片、语音、视频类型,content是mediaID
}

消息自动回复的信息

type MessageHandler

type MessageHandler interface {
	ServeMessage(http.ResponseWriter, *Request)
}

微信服务器推送过来的消息(事件)处理接口

type MessageHandlerFunc

type MessageHandlerFunc func(http.ResponseWriter, *Request)

func (MessageHandlerFunc) ServeMessage

func (fn MessageHandlerFunc) ServeMessage(w http.ResponseWriter, r *Request)

type MessageHeader

type MessageHeader struct {
	ToUserName   string `xml:"ToUserName"   json:"ToUserName"`
	FromUserName string `xml:"FromUserName" json:"FromUserName"`
	CreateTime   int64  `xml:"CreateTime"   json:"CreateTime"`
	MsgType      string `xml:"MsgType"      json:"MsgType"`
}

微信服务器推送过来的消息(事件)通用的消息头

type MessageServeMux

type MessageServeMux struct {
	// contains filtered or unexported fields
}

MessageServeMux 实现了一个简单的消息(事件)路由器, 同时也是一个 MessageHandler 的实现.

func NewMessageServeMux

func NewMessageServeMux() *MessageServeMux

func (*MessageServeMux) DefaultEventHandle

func (mux *MessageServeMux) DefaultEventHandle(handler MessageHandler)

注册事件的默认 MessageHandler.

func (*MessageServeMux) DefaultEventHandleFunc

func (mux *MessageServeMux) DefaultEventHandleFunc(handler func(http.ResponseWriter, *Request))

注册事件的默认 MessageHandler.

func (*MessageServeMux) DefaultMessageHandle

func (mux *MessageServeMux) DefaultMessageHandle(handler MessageHandler)

注册消息的默认 MessageHandler.

func (*MessageServeMux) DefaultMessageHandleFunc

func (mux *MessageServeMux) DefaultMessageHandleFunc(handler func(http.ResponseWriter, *Request))

注册消息的默认 MessageHandler.

func (*MessageServeMux) EventHandle

func (mux *MessageServeMux) EventHandle(eventType string, handler MessageHandler)

注册特定类型事件的 MessageHandler.

func (*MessageServeMux) EventHandleFunc

func (mux *MessageServeMux) EventHandleFunc(eventType string, handler func(http.ResponseWriter, *Request))

注册特定类型事件的 MessageHandler.

func (*MessageServeMux) MessageHandle

func (mux *MessageServeMux) MessageHandle(msgType string, handler MessageHandler)

注册特定类型消息的 MessageHandler.

func (*MessageServeMux) MessageHandleFunc

func (mux *MessageServeMux) MessageHandleFunc(msgType string, handler func(http.ResponseWriter, *Request))

注册特定类型消息的 MessageHandler.

func (*MessageServeMux) ServeMessage

func (mux *MessageServeMux) ServeMessage(w http.ResponseWriter, r *Request)

MessageServeMux 实现了 MessageHandler 接口.

type MixedMessage

type MixedMessage struct {
	XMLName struct{} `xml:"xml" json:"-"`
	MessageHeader

	MsgId int64 `xml:"MsgId" json:"MsgId"`
	MsgID int64 `xml:"MsgID" json:"MsgID"` // 群发消息和模板消息的消息ID, 而不是此事件消息的ID

	Content      string  `xml:"Content"      json:"Content"`
	MediaId      string  `xml:"MediaId"      json:"MediaId"`
	PicURL       string  `xml:"PicUrl"       json:"PicUrl"`
	Format       string  `xml:"Format"       json:"Format"`
	Recognition  string  `xml:"Recognition"  json:"Recognition"`
	ThumbMediaId string  `xml:"ThumbMediaId" json:"ThumbMediaId"`
	LocationX    float64 `xml:"Location_X"   json:"Location_X"`
	LocationY    float64 `xml:"Location_Y"   json:"Location_Y"`
	Scale        int     `xml:"Scale"        json:"Scale"`
	Label        string  `xml:"Label"        json:"Label"`
	Title        string  `xml:"Title"        json:"Title"`
	Description  string  `xml:"Description"  json:"Description"`
	URL          string  `xml:"Url"          json:"Url"`

	Event    string `xml:"Event"    json:"Event"`
	EventKey string `xml:"EventKey" json:"EventKey"`

	ScanCodeInfo struct {
		ScanType   string `xml:"ScanType"   json:"ScanType"`
		ScanResult string `xml:"ScanResult" json:"ScanResult"`
	} `xml:"ScanCodeInfo" json:"ScanCodeInfo"`

	SendPicsInfo struct {
		Count   int `xml:"Count" json:"Count"`
		PicList []struct {
			PicMD5Sum string `xml:"PicMd5Sum" json:"PicMd5Sum"`
		} `xml:"PicList>item,omitempty" json:"PicList,omitempty"`
	} `xml:"SendPicsInfo" json:"SendPicsInfo"`

	SendLocationInfo struct {
		LocationX float64 `xml:"Location_X" json:"Location_X"`
		LocationY float64 `xml:"Location_Y" json:"Location_Y"`
		Scale     int     `xml:"Scale"      json:"Scale"`
		Label     string  `xml:"Label"      json:"Label"`
		PoiName   string  `xml:"Poiname"    json:"Poiname"`
	} `xml:"SendLocationInfo" json:"SendLocationInfo"`

	Ticket      string  `xml:"Ticket"      json:"Ticket"`
	Latitude    float64 `xml:"Latitude"    json:"Latitude"`
	Longitude   float64 `xml:"Longitude"   json:"Longitude"`
	Precision   float64 `xml:"Precision"   json:"Precision"`
	Status      string  `xml:"Status"      json:"Status"`
	TotalCount  int     `xml:"TotalCount"  json:"TotalCount"`
	FilterCount int     `xml:"FilterCount" json:"FilterCount"`
	SentCount   int     `xml:"SentCount"   json:"SentCount"`
	ErrorCount  int     `xml:"ErrorCount"  json:"ErrorCount"`

	// merchant
	OrderId     string `xml:"OrderId"     json:"OrderId"`
	OrderStatus int    `xml:"OrderStatus" json:"OrderStatus"`
	ProductId   string `xml:"ProductId"   json:"ProductId"`
	SKUInfo     string `xml:"SkuInfo"     json:"SkuInfo"`

	// card
	CardId          string `xml:"CardId"          json:"CardId"`
	IsGiveByFriend  int    `xml:"IsGiveByFriend"  json:"IsGiveByFriend"`
	FriendUserName  string `xml:"FriendUserName"  json:"FriendUserName"`
	UserCardCode    string `xml:"UserCardCode"    json:"UserCardCode"`
	OldUserCardCode string `xml:"OldUserCardCode" json:"OldUserCardCode"`
	ConsumeSource   string `xml:"ConsumeSource"   json:"ConsumeSource"`
	OuterId         int64  `xml:"OuterId"         json:"OuterId"`

	// poi
	UniqId string `xml:"UniqId" json:"UniqId"`
	PoiId  int64  `xml:"PoiId"  json:"PoiId"`
	Result string `xml:"Result" json:"Result"`
	Msg    string `xml:"Msg"    json:"Msg"`

	// dkf
	KfAccount     string `xml:"KfAccount"     json:"KfAccount"`
	FromKfAccount string `xml:"FromKfAccount" json:"FromKfAccount"`
	ToKfAccount   string `xml:"ToKfAccount"   json:"ToKfAccount"`

	// shakearound
	ChosenBeacon  ChosenBeacon   `xml:"ChosenBeacon"                         json:"ChosenBeacon"`
	AroundBeacons []AroundBeacon `xml:"AroundBeacons>AroundBeacon,omitempty" json:"AroundBeacons,omitempty"`

	// bizwifi
	ConnectTime int64  `xml:"ConnectTime" json:"ConnectTime"`
	ExpireTime  int64  `xml:"ExpireTime"  json:"ExpireTime"`
	VendorId    string `xml:"VendorId"    json:"VendorId"`
	PlaceId     int64  `xml:"PlaceId"     json:"PlaceId"`
	DeviceNo    string `xml:"DeviceNo"    json:"DeviceNo"`
}

微信服务器推送过来的消息(事件)的合集.

type MultiServerFrontend

type MultiServerFrontend struct {
	// contains filtered or unexported fields
}

多个 Server 的前端, http.Handler 的实现.

MultiServerFrontend 可以处理多个公众号的消息(事件), 但是要求在回调 URL 上加上一个
查询参数(参数名与 urlServerQueryName 一致), 通过这个参数的值来索引对应的 Server.

例如回调 URL 为(urlServerQueryName == "wechat_server"):
  http://www.xxx.com/weixin?wechat_server=1234567890
那么就可以在后端调用
 MultiServerFrontend.SetServer("1234567890", Server)
来增加一个 Server 来处理 wechat_server=1234567890 的消息(事件).

MultiServerFrontend 并发安全, 可以在运行中动态增加和删除 Server.

func NewMultiServerFrontend

func NewMultiServerFrontend(urlServerQueryName string, errHandler ErrorHandler, interceptor Interceptor) *MultiServerFrontend

NewMultiServerFrontend 创建一个新的 MultiServerFrontend.

urlServerQueryName: 回调 URL 上参数名, 这个参数的值就是索引 Server 的 key
errHandler:         错误处理 handler, 可以为 nil
interceptor:        拦截器, 可以为 nil

func (*MultiServerFrontend) DeleteAllServer

func (frontend *MultiServerFrontend) DeleteAllServer()

func (*MultiServerFrontend) DeleteServer

func (frontend *MultiServerFrontend) DeleteServer(serverKey string)

func (*MultiServerFrontend) ServeHTTP

func (frontend *MultiServerFrontend) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*MultiServerFrontend) SetServer

func (frontend *MultiServerFrontend) SetServer(serverKey string, server Server) (err error)

type MultipartFormField

type MultipartFormField struct {
	ContentType int // 0:文件field, 1:普通的文本field
	FieldName   string
	FileName    string // ContentType == 0 时有效
	Value       io.Reader
}

type NewsInfo

type NewsInfo struct {
	ArticleList []Article `json:"list,omitempty"`
}

type ReplyInfo

type ReplyInfo struct {
	Type string `json:"type"` // 自动回复的类型。关注后自动回复和消息自动回复的类型仅支持文本(text)、图片(img)、语音(voice)、视频(video),关键词自动回复则还多了图文消息

	// 下面两个字段不会同时有效, 根据 ReplyInfo.Type 来做选择
	Content  string    `json:"content,omitempty"`   // 对于文本类型,content是文本内容,对于图片、语音、视频类型,content是mediaID
	NewsInfo *NewsInfo `json:"news_info,omitempty"` // 图文消息的信息
}

关键词回复信息

type Request

type Request struct {
	Token string // 请求消息所属公众号的 Token

	HttpRequest *http.Request // 可以为 nil, 因为某些 http 框架没有提供此参数
	QueryValues url.Values    // 回调请求 URL 中的查询参数集合

	Signature string // 回调请求 URL 中的签名: signature
	Timestamp int64  // 回调请求 URL 中的时间戳: timestamp
	Nonce     string // 回调请求 URL 中的随机数: nonce

	EncryptType string        // 请求 URL 中的加密方式: encrypt_type
	RawMsgXML   []byte        // 消息的 XML 文本, 对于加密模式是解密后的消息
	MixedMsg    *MixedMessage // RawMsgXML 解析后的消息

	// 下面的字段是 AES 模式才有的
	MsgSignature string   // 请求 URL 中的消息体签名: msg_signature
	AESKey       [32]byte // 当前消息 AES 加密的 key
	Random       []byte   // 当前消息加密时所用的 random, 16 bytes
	AppId        string   // 当前消息加密时所用的 AppId
}

消息(事件)请求信息

type RequestHttpBody

type RequestHttpBody struct {
	XMLName struct{} `xml:"xml" json:"-"`

	ToUserName   string `xml:"ToUserName" json:"ToUserName"`
	EncryptedMsg string `xml:"Encrypt"    json:"Encrypt"`
}

安全模式, 微信服务器推送过来的 http body

type ResponseHttpBody

type ResponseHttpBody struct {
	XMLName struct{} `xml:"xml" json:"-"`

	EncryptedMsg string `xml:"Encrypt"      json:"Encrypt"`
	MsgSignature string `xml:"MsgSignature" json:"MsgSignature"`
	Timestamp    int64  `xml:"TimeStamp"    json:"TimeStamp"`
	Nonce        string `xml:"Nonce"        json:"Nonce"`
}

安全模式下回复消息的 http body

type Server

type Server interface {
	Token() string                          // 获取公众号的 Token, 用于校验签名.
	CurrentAESKey() [32]byte                // 获取当前的 AES 加密 Key
	LastAESKey() (key [32]byte, valid bool) // 获取上一个 AES 加密 Key

	OriId() string // 公众号的原始ID, 用于约束消息的 ToUserName, 如果为空表示不约束
	AppId() string // AppId, 用于约束消息的 AppId, 如果为空表示不约束

	MessageHandler() MessageHandler // 获取 MessageHandler
}

type ServerFrontend

type ServerFrontend struct {
	// contains filtered or unexported fields
}

ServerFrontend 实现了 http.Handler, 处理一个公众号的消息(事件)请求.

func NewServerFrontend

func NewServerFrontend(server Server, errHandler ErrorHandler, interceptor Interceptor) *ServerFrontend

NOTE: errHandler, interceptor 均可以为 nil

func (*ServerFrontend) ServeHTTP

func (frontend *ServerFrontend) ServeHTTP(w http.ResponseWriter, r *http.Request)

Directories

Path Synopsis
帐号管理接口.
帐号管理接口.
微信连Wi-Fi
微信连Wi-Fi
微信卡券接口
微信卡券接口
datacube
see github.com/chanxuehong/wechat/mp/datacube
see github.com/chanxuehong/wechat/mp/datacube
公众号第三方平台接口
公众号第三方平台接口
数据统计接口.
数据统计接口.
card
卡券数据统计接口
卡券数据统计接口
dkf
多客服接口.
多客服接口.
js-sdk 服务器端接口.
js-sdk 服务器端接口.
永久素材API.
永久素材API.
临时素材API.
临时素材API.
自定义菜单接口.
自定义菜单接口.
消息(接收和发送)接口.
消息(接收和发送)接口.
custom
客服主动回复消息.
客服主动回复消息.
mass
群发消息.
群发消息.
mass/mass2all
群发给所有用户的消息数据结构.
群发给所有用户的消息数据结构.
mass/mass2group
群发给分组的消息数据结构.
群发给分组的消息数据结构.
mass/mass2users
群发给用户列表的消息数据结构.
群发给用户列表的消息数据结构.
mass/preview
预览接口的消息数据结构.
预览接口的消息数据结构.
request
被动接收基本的消息(事件).
被动接收基本的消息(事件).
response
被动回复用户消息.
被动回复用户消息.
template
模板消息接口.
模板消息接口.
Poi 门店管理接口, v2.2.3
Poi 门店管理接口, v2.2.3
摇一摇周边
摇一摇周边
用户管理接口.
用户管理接口.
oauth2
网页授权获取用户基本信息
网页授权获取用户基本信息

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL