Documentation ¶
Overview ¶
微信公众平台(订阅号&服务号) SDK 的核心库
Index ¶
- Constants
- type AccessTokenServer
- type Client
- func (clt *Client) GetJSON(incompleteURL string, response interface{}) (err error)
- func (clt *Client) PostJSON(incompleteURL string, request interface{}, response interface{}) (err error)
- func (clt *Client) PostMultipartForm(incompleteURL string, fields []MultipartFormField, response interface{}) (err error)
- type Context
- func (ctx *Context) AESResponse(msg interface{}, timestamp int64, nonce string, random []byte) (err error)
- func (ctx *Context) Abort()
- func (ctx *Context) Get(key string) (value interface{}, exists bool)
- func (ctx *Context) IsAborted() bool
- func (ctx *Context) MustGet(key string) interface{}
- func (ctx *Context) Next()
- func (ctx *Context) NoneResponse() (err error)
- func (ctx *Context) RawResponse(msg interface{}) (err error)
- func (ctx *Context) Set(key string, value interface{})
- func (ctx *Context) SetHandlers(handlers HandlerChain)
- type DefaultAccessTokenServer
- type Error
- type ErrorHandler
- type ErrorHandlerFunc
- type EventType
- type Handler
- type HandlerChain
- type HandlerFunc
- type MixedMsg
- type MsgHeader
- type MsgType
- type MultipartFormField
- type ServeMux
- func (mux *ServeMux) DefaultEventHandle(handlers ...Handler)
- func (mux *ServeMux) DefaultEventHandleFunc(handlers ...func(*Context))
- func (mux *ServeMux) DefaultMsgHandle(handlers ...Handler)
- func (mux *ServeMux) DefaultMsgHandleFunc(handlers ...func(*Context))
- func (mux *ServeMux) EventHandle(eventType EventType, handlers ...Handler)
- func (mux *ServeMux) EventHandleFunc(eventType EventType, handlers ...func(*Context))
- func (mux *ServeMux) MsgHandle(msgType MsgType, handlers ...Handler)
- func (mux *ServeMux) MsgHandleFunc(msgType MsgType, handlers ...func(*Context))
- func (mux *ServeMux) ServeMsg(ctx *Context)
- func (mux *ServeMux) Use(middlewares ...Handler)
- func (mux *ServeMux) UseForEvent(middlewares ...Handler)
- func (mux *ServeMux) UseForMsg(middlewares ...Handler)
- func (mux *ServeMux) UseFunc(middlewares ...func(*Context))
- func (mux *ServeMux) UseFuncForEvent(middlewares ...func(*Context))
- func (mux *ServeMux) UseFuncForMsg(middlewares ...func(*Context))
- type Server
Examples ¶
Constants ¶
const ( ErrCodeOK = 0 ErrCodeInvalidCredential = 40001 // access_token 过期错误码 ErrCodeAccessTokenExpired = 42001 // access_token 过期错误码(maybe!!!) )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AccessTokenServer ¶
type AccessTokenServer interface { Token() (token string, err error) // 请求中控服务器返回缓存的 access_token RefreshToken(currentToken string) (token string, err error) // 请求中控服务器刷新 access_token IID01332E16DF5011E5A9D5A4DB30FED8E1() // 接口标识, 没有实际意义 }
access_token 中控服务器接口.
type Client ¶
type Client struct { AccessTokenServer HttpClient *http.Client }
func NewClient ¶
func NewClient(srv AccessTokenServer, clt *http.Client) *Client
NewClient 创建一个新的 Client.
如果 clt == nil 则默认用 util.DefaultHttpClient
func (*Client) GetJSON ¶
GetJSON HTTP 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)
PostJSON 用 encoding/json 把 request marshal 为 JSON, HTTP 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)
PostMultipartForm 通用上传接口.
--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 Context ¶
type Context struct { ResponseWriter http.ResponseWriter Request *http.Request QueryParams url.Values // 回调请求 URL 的查询参数集合 EncryptType string // 回调请求 URL 的加密方式参数: encrypt_type MsgSignature string // 回调请求 URL 的消息体签名参数: msg_signature Signature string // 回调请求 URL 的签名参数: signature Timestamp int64 // 回调请求 URL 的时间戳参数: timestamp Nonce string // 回调请求 URL 的随机数参数: nonce MsgCiphertext []byte // 消息的密文文本 MsgPlaintext []byte // 消息的明文文本, xml格式 MixedMsg *MixedMsg // 消息 Token string // 当前消息所属公众号的 Token AESKey []byte // 当前消息加密所用的 aes-key, read-only!!! Random []byte // 当前消息加密所用的 random, 16-bytes AppId string // 当前消息加密所用的 AppId // contains filtered or unexported fields }
Context 是 Handler 处理消息(事件)的上下文环境. 非并发安全!
func (*Context) AESResponse ¶
func (ctx *Context) AESResponse(msg interface{}, timestamp int64, nonce string, random []byte) (err error)
AESResponse 回复aes加密的消息给微信服务器.
msg: 经过 encoding/xml.Marshal 得到的结果符合微信消息格式的任何数据结构 timestamp: 时间戳, 如果为 0 则默认使用 Context.Timestamp nonce: 随机数, 如果为 "" 则默认使用 Context.Nonce random: 16字节的随机字符串, 如果为 nil 则默认使用 Context.Random
func (*Context) Abort ¶
func (ctx *Context) Abort()
Abort 阻止系统调用当前 handler 后续的 handlers, 即当前的 handler 处理完毕就返回, 一般在 middleware 中调用.
func (*Context) Get ¶
Get 返回 Context 中 key 对应的 value, 如果 key 存在的返回 (value, true), 否则返回 (nil, false).
func (*Context) Next ¶
func (ctx *Context) Next()
Next 中断当前 handler 程序逻辑执行其后续的 handlers, 一般在 middleware 中调用.
func (*Context) NoneResponse ¶
NoneResponse 表示没有消息回复给微信服务器.
func (*Context) RawResponse ¶
RawResponse 回复明文消息给微信服务器.
msg: 经过 encoding/xml.Marshal 得到的结果符合微信消息格式的任何数据结构
func (*Context) SetHandlers ¶
func (ctx *Context) SetHandlers(handlers HandlerChain)
SetHandlers 设置 handlers 给 Context.Next() 调用, 务必在 Context.Next() 调用之前设置, 否则会 panic.
NOTE: 此方法一般用不到, 除非你自己实现一个 Handler 给 Server 使用, 参考 ServeMux.
type DefaultAccessTokenServer ¶
type DefaultAccessTokenServer struct {
// contains filtered or unexported fields
}
DefaultAccessTokenServer 实现了 AccessTokenServer 接口.
NOTE: 1. 用于单进程环境. 2. 因为 DefaultAccessTokenServer 同时也是一个简单的中控服务器, 而不是仅仅实现 AccessTokenServer 接口, 所以整个系统只能存在一个 DefaultAccessTokenServer 实例!
func NewDefaultAccessTokenServer ¶
func NewDefaultAccessTokenServer(appId, appSecret string, httpClient *http.Client) (srv *DefaultAccessTokenServer)
NewDefaultAccessTokenServer 创建一个新的 DefaultAccessTokenServer, 如果 httpClient == nil 则默认使用 util.DefaultHttpClient.
func (*DefaultAccessTokenServer) IID01332E16DF5011E5A9D5A4DB30FED8E1 ¶
func (srv *DefaultAccessTokenServer) IID01332E16DF5011E5A9D5A4DB30FED8E1()
func (*DefaultAccessTokenServer) RefreshToken ¶
func (srv *DefaultAccessTokenServer) RefreshToken(currentToken string) (token string, err error)
func (*DefaultAccessTokenServer) Token ¶
func (srv *DefaultAccessTokenServer) Token() (token string, err error)
type ErrorHandler ¶
type ErrorHandler interface {
ServeError(http.ResponseWriter, *http.Request, error)
}
var DefaultErrorHandler ErrorHandler = ErrorHandlerFunc(defaultErrorHandlerFunc)
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 HandlerChain ¶
type HandlerChain []Handler
type HandlerFunc ¶
type HandlerFunc func(*Context)
func (HandlerFunc) ServeMsg ¶
func (fn HandlerFunc) ServeMsg(ctx *Context)
type MixedMsg ¶
type MixedMsg struct { XMLName struct{} `xml:"xml" json:"-"` MsgHeader EventType EventType `xml:"Event" json:"Event"` MsgId int64 `xml:"MsgId" json:"MsgId"` // request Content string `xml:"Content" json:"Content"` // request MediaId string `xml:"MediaId" json:"MediaId"` // request PicURL string `xml:"PicUrl" json:"PicUrl"` // request Format string `xml:"Format" json:"Format"` // request Recognition string `xml:"Recognition" json:"Recognition"` // request ThumbMediaId string `xml:"ThumbMediaId" json:"ThumbMediaId"` // request LocationX float64 `xml:"Location_X" json:"Location_X"` // request LocationY float64 `xml:"Location_Y" json:"Location_Y"` // request Scale int `xml:"Scale" json:"Scale"` // request Label string `xml:"Label" json:"Label"` // request Title string `xml:"Title" json:"Title"` // request Description string `xml:"Description" json:"Description"` // request URL string `xml:"Url" json:"Url"` // request EventKey string `xml:"EventKey" json:"EventKey"` // request, menu Ticket string `xml:"Ticket" json:"Ticket"` // request Latitude float64 `xml:"Latitude" json:"Latitude"` // request Longitude float64 `xml:"Longitude" json:"Longitude"` // request Precision float64 `xml:"Precision" json:"Precision"` // request // menu MenuId int64 `xml:"MenuId" json:"MenuId"` ScanCodeInfo *struct { ScanType string `xml:"ScanType" json:"ScanType"` ScanResult string `xml:"ScanResult" json:"ScanResult"` } `xml:"ScanCodeInfo,omitempty" json:"ScanCodeInfo,omitempty"` 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,omitempty" json:"SendPicsInfo,omitempty"` 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,omitempty" json:"SendLocationInfo,omitempty"` MsgID int64 `xml:"MsgID" json:"MsgID"` // template, mass Status string `xml:"Status" json:"Status"` // template, mass TotalCount int `xml:"TotalCount,omitempty" json:"TotalCount"` FilterCount int `xml:"FilterCount" json:"FilterCount"` SentCount int `xml:"SentCount" json:"SentCount"` ErrorCount int `xml:"ErrorCount" json:"ErrorCount"` CopyrightCheckResult *struct { Count int `xml:"Count" json:"Count"` ResultList []struct { Item *struct { ArticleIdx int `xml:"ArticleIdx" json:"ArticleIdx"` UserDeclareState int `xml:"UserDeclareState" json:"UserDeclareState"` AuditState int `xml:"AuditState" json:"AuditState"` OriginalArticleUrl string `xml:"OriginalArticleUrl" json:"OriginalArticleUrl"` OriginalArticleType int `xml:"OriginalArticleType" json:"OriginalArticleType"` CanReprint int `xml:"CanReprint" json:"CanReprint"` NeedReplaceContent int `xml:"NeedReplaceContent" json:"NeedReplaceContent"` NeedShowReprintSource int `xml:"NeedShowReprintSource" json:"NeedShowReprintSource"` } `xml:"item" json:"item"` } `xml:"ResultList,omitempty" json:"ResultList"` CheckState int `xml:"CheckState" json:"CheckState"` } `xml:"CopyrightCheckResult" json:"CopyrightCheckResult,omitempty"` ArticleUrlResult *struct { Count int `xml:"Count" json:"Count"` ResultList []*struct { Item *struct { ArticleIdx int `xml:"ArticleIdx" json:"ArticleIdx"` ArticleUrl string `xml:"ArticleUrl" json:"ArticleUrl"` } `xml:"item" json:"item"` } `xml:"ResultList" json:"ResultList"` } `xml:"ArticleUrlResult" json:"ArticleUrlResult,omitempty"` // shakearound 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"` } `xml:"ChosenBeacon,omitempty" json:"ChosenBeacon,omitempty"` AroundBeacons []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"` } `xml:"AroundBeacons>AroundBeacon,omitempty" json:"AroundBeacons,omitempty"` // contains filtered or unexported fields }
微信服务器推送过来的消息(事件)的合集.
type MsgHeader ¶
type MsgHeader struct { ToUserName string `xml:"ToUserName" json:"ToUserName"` FromUserName string `xml:"FromUserName" json:"FromUserName"` CreateTime int64 `xml:"CreateTime" json:"CreateTime"` MsgType MsgType `xml:"MsgType" json:"MsgType"` }
微信服务器推送过来的消息(事件)的通用消息头.
type MultipartFormField ¶
type ServeMux ¶
type ServeMux struct {
// contains filtered or unexported fields
}
ServeMux 是一个消息(事件)路由器, 同时也是一个 Handler 的实现.
NOTE: ServeMux 非并发安全, 如果需要并发安全的 Handler, 可以参考 ServeMux 实现一个.
func NewServeMux ¶
func NewServeMux() *ServeMux
func (*ServeMux) DefaultEventHandle ¶
DefaultEventHandle 设置 handlers 以处理没有匹配到具体类型的 HandlerChain 的事件.
func (*ServeMux) DefaultEventHandleFunc ¶
DefaultEventHandleFunc 设置 handlers 以处理没有匹配到具体类型的 HandlerChain 的事件.
func (*ServeMux) DefaultMsgHandle ¶
DefaultMsgHandle 设置 handlers 以处理没有匹配到具体类型的 HandlerChain 的消息.
func (*ServeMux) DefaultMsgHandleFunc ¶
DefaultMsgHandleFunc 设置 handlers 以处理没有匹配到具体类型的 HandlerChain 的消息.
func (*ServeMux) EventHandle ¶
EventHandle 设置 handlers 以处理特定类型的事件.
func (*ServeMux) EventHandleFunc ¶
EventHandleFunc 设置 handlers 以处理特定类型的事件.
func (*ServeMux) MsgHandleFunc ¶
MsgHandleFunc 设置 handlers 以处理特定类型的消息.
func (*ServeMux) UseForEvent ¶
UseForEvent 注册(新增) middlewares 使其在所有事件的 Handler 之前处理该处理事件.
func (*ServeMux) UseFuncForEvent ¶
UseFuncForEvent 注册(新增) middlewares 使其在所有事件的 Handler 之前处理该处理事件.
func (*ServeMux) UseFuncForMsg ¶
UseFuncForMsg 注册(新增) middlewares 使其在所有消息的 Handler 之前处理该处理消息.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server 用于处理微信服务器的回调请求, 并发安全!
通常情况下一个 Server 实例用于处理一个公众号的消息(事件), 此时建议指定 oriId(原始ID) 和 appId(明文模式下无需指定) 用于约束消息(事件); 特殊情况下也可以一个 Server 实例用于处理多个公众号的消息(事件), 此时要求这些公众号的 token 是一样的, 并且 oriId 和 appId 必须设置为 "".
func NewServer ¶
func NewServer(oriId, appId, token, base64AESKey string, handler Handler, errorHandler ErrorHandler) (srv *Server)
NewServer 创建一个新的 Server.
oriId: 可选; 公众号的原始ID(微信公众号管理后台查看), 如果设置了值则该Server只能处理 ToUserName 为该值的公众号的消息(事件); appId: 可选; 公众号的AppId, 如果设置了值则安全模式时该Server只能处理 AppId 为该值的公众号的消息(事件); token: 必须; 公众号用于验证签名的token; base64AESKey: 可选; aes加密解密key, 43字节长(base64编码, 去掉了尾部的'='), 安全模式必须设置; handler: 必须; 处理微信服务器推送过来的消息(事件)的Handler; errorHandler: 可选; 用于处理Server在处理消息(事件)过程中产生的错误, 如果没有设置则默认使用 DefaultErrorHandler.
func (*Server) ServeHTTP ¶
ServeHTTP 处理微信服务器的回调请求, query 参数可以为 nil.
Example ¶
package main import ( "net/http" "github.com/chanxuehong/wechat/mp/core" ) func main() { mux := core.NewServeMux() // 创建 core.Handler, 也可以用自己实现的 core.Handler // 注册消息(事件)处理 Handler, 都不是必须的! { mux.UseFunc(func(ctx *core.Context) { // 注册中间件, 处理所有的消息(事件) // TODO: 中间件处理逻辑 }) mux.UseFuncForMsg(func(ctx *core.Context) { // 注册中间件, 处理所有的消息 // TODO: 中间件处理逻辑 }) mux.UseFuncForEvent(func(ctx *core.Context) { // 注册中间件, 处理所有的事件 // TODO: 中间件处理逻辑 }) mux.DefaultMsgHandleFunc(func(ctx *core.Context) { // 设置默认消息处理 Handler // TODO: 消息处理逻辑 }) mux.DefaultEventHandleFunc(func(ctx *core.Context) { // 设置默认事件处理 Handler // TODO: 事件处理逻辑 }) mux.MsgHandleFunc("{MsgType}", func(ctx *core.Context) { // 设置具体类型的消息处理 Handler // TODO: 消息处理逻辑 }) mux.EventHandleFunc("{EventType}", func(ctx *core.Context) { // 设置具体类型的事件处理 Handler // TODO: 事件处理逻辑 }) } // 创建 Server, 设置正确的参数. // 通常一个 Server 对应一个公众号, 当然一个 Server 也可以对应多个公众号, 这个时候 oriId 和 appId 都应该设置为空值! srv := core.NewServer("{oriId}", "{appId}", "{token}", "{base64AESKey}", mux, nil) // 在回调 URL 的 Handler 里处理消息(事件) http.HandleFunc("/wechat_callback", func(w http.ResponseWriter, r *http.Request) { srv.ServeHTTP(w, r, nil) }) }
Output: