package wechat import ( "bytes" "encoding/json" "encoding/xml" "errors" "fmt" "math/rand" "sort" "strings" "sync" "time" "git.chuangxin1.com/cx/util" ) const ( // TokenExpires token expires time 1 hours TokenExpires = 60 * 60 // BaseURL api host BaseURL = `https://api.weixin.qq.com` // OpenURL open host OpenURL = `https://open.weixin.qq.com` ) // ResponseMsg response type ResponseMsg struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` } // Response response type Response struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` // token AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` // openid RefreshToken string `json:"refresh_token"` OpenID string `json:"openid"` Scope string `json:"scope"` // user info NickName string `json:"nickname"` Sex string `json:"sex"` Province string `json:"province"` City string `json:"city"` Country string `json:"country"` HeadImgURL string `json:"headimgurl"` Privilege string `json:"privilege"` UnionID string `json:"unionid"` // template message MsgID int64 `json:"msgid"` // jsapi_ticket Ticket string `json:"ticket"` } // FormSignature signature type FormSignature struct { TimeStamp string `form:"timestamp" json:"timestamp"` Nonce string `form:"nonce" json:"nonce"` Signature string `form:"signature" json:"signature"` Echostr string `form:"echostr" json:"echostr"` } // Message message type Message struct { XMLName xml.Name `xml:"xml"` ToUserName string `xml:"ToUserName" json:"ToUserName"` FromUserName string `xml:"FromUserName" json:"FromUserName"` CreateTime int32 `xml:"CreateTime" json:"CreateTime"` MsgType string `xml:"MsgType" json:"MsgType"` MsgID int64 `xml:"MsgId" json:"MsgId"` } // EventTemplateReply event reply type EventTemplateReply struct { XMLName xml.Name `xml:"xml"` ToUserName string `xml:"ToUserName"` FromUserName string `xml:"FromUserName"` CreateTime string `xml:"CreateTime"` MsgType string `xml:"MsgType"` Event string `xml:"Event"` MsgID string `xml:"MsgID"` Status string `xml:"Status"` } var ( cache sync.Map ) // Sign 微信计算签名的函数 func Sign(req map[string]interface{}, key string) (sign string) { keys := make([]string, 0) for k := range req { keys = append(keys, k) } sort.Strings(keys) var s string for _, k := range keys { value := fmt.Sprintf("%v", req[k]) if value != "" { s = s + k + "=" + value + "&" } } if key != "" { s = s + "key=" + key } sign = strings.ToUpper(util.MD5(s)) return } // Random 指定长度的随机字符串(字母或数字) func Random(n int) string { str := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" bytes := []byte(str) result := []byte{} r := rand.New(rand.NewSource(time.Now().UnixNano())) n1 := len(bytes) for i := 0; i < n; i++ { result = append(result, bytes[r.Intn(n1)]) } return string(result) } func makeSignature(token, signature, timestamp, nonce string) bool { sl := []string{token, timestamp, nonce} sort.Strings(sl) return strings.Compare(signature, util.SHA1(strings.Join(sl, ""))) == 0 } func checkErrorWithBody(msg util.Message) (body []byte, err error) { if msg.StatusCode == 200 { var res ResponseMsg err = json.Unmarshal(msg.Body, &res) if err == nil { if res.ErrCode != 0 { err = errors.New(res.ErrMsg) } else { body = msg.Body } } } else { err = errors.New(`HTTP StatusCode not 200`) } return } func checkError(msg util.Message) (res Response, err error) { if msg.StatusCode == 200 { err = json.Unmarshal(msg.Body, &res) if err == nil { if res.ErrCode != 0 { err = errors.New(res.ErrMsg) } } } else { err = errors.New(`HTTP StatusCode not 200`) } return } func getJSON(uri string) (res Response, err error) { var msg util.Message if msg, err = util.Get(uri, "", "", map[string]string{}); err != nil { return } res, err = checkError(msg) return } func getBody(uri string) (body []byte, err error) { var msg util.Message if msg, err = util.Get(uri, "", "", map[string]string{}); err != nil { return } body, err = checkErrorWithBody(msg) return } func postXML(url string, data []byte) (res Response, err error) { var ( msg util.Message headers = make(map[string]string) ) headers["Accept"] = "application/json" headers["Content-Type"] = "application/xml; charset=utf-8" msg, err = util.Post(url, "", "", headers, bytes.NewReader(data)) if err != nil { return } res, err = checkError(msg) return } func postJSON(url string, data []byte) (res Response, err error) { var ( msg util.Message headers = make(map[string]string) ) headers["Accept"] = "application/json" headers["Content-Type"] = "application/json; charset=utf-8" msg, err = util.Post(url, "", "", headers, bytes.NewReader(data)) if err != nil { return } res, err = checkError(msg) return } func postBody(uri string, data []byte) (body []byte, err error) { var ( msg util.Message headers = make(map[string]string) ) headers["Accept"] = "application/json" headers["Content-Type"] = "application/json; charset=utf-8" msg, err = util.Post(uri, "", "", headers, bytes.NewReader(data)) if err != nil { return } body, err = checkErrorWithBody(msg) return }