wechat.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package wechat
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "encoding/xml"
  6. "errors"
  7. "fmt"
  8. "sort"
  9. "strings"
  10. "sync"
  11. "git.chuangxin1.com/cx/util"
  12. )
  13. const (
  14. // TokenExpires token expires time 1 hours
  15. TokenExpires = 60 * 60
  16. // BaseURL api host
  17. BaseURL = `https://api.weixin.qq.com`
  18. // OpenURL open host
  19. OpenURL = `https://open.weixin.qq.com`
  20. )
  21. // ResponseMsg response
  22. type ResponseMsg struct {
  23. ErrCode int `json:"errcode"`
  24. ErrMsg string `json:"errmsg"`
  25. }
  26. // Response response
  27. type Response struct {
  28. ErrCode int `json:"errcode"`
  29. ErrMsg string `json:"errmsg"`
  30. // token
  31. AccessToken string `json:"access_token"`
  32. ExpiresIn int `json:"expires_in"`
  33. // openid
  34. RefreshToken string `json:"refresh_token"`
  35. OpenID string `json:"openid"`
  36. Scope string `json:"scope"`
  37. // user info
  38. NickName string `json:"nickname"`
  39. Sex string `json:"sex"`
  40. Province string `json:"province"`
  41. City string `json:"city"`
  42. Country string `json:"country"`
  43. HeadImgURL string `json:"headimgurl"`
  44. Privilege string `json:"privilege"`
  45. UnionID string `json:"unionid"`
  46. // template message
  47. MsgID int64 `json:"msgid"`
  48. }
  49. // FormSignature signature
  50. type FormSignature struct {
  51. TimeStamp string `form:"timestamp" json:"timestamp"`
  52. Nonce string `form:"nonce" json:"nonce"`
  53. Signature string `form:"signature" json:"signature"`
  54. Echostr string `form:"echostr" json:"echostr"`
  55. }
  56. // Message message
  57. type Message struct {
  58. XMLName xml.Name `xml:"xml"`
  59. ToUserName string `xml:"ToUserName" json:"ToUserName"`
  60. FromUserName string `xml:"FromUserName" json:"FromUserName"`
  61. CreateTime int32 `xml:"CreateTime" json:"CreateTime"`
  62. MsgType string `xml:"MsgType" json:"MsgType"`
  63. MsgID int64 `xml:"MsgId" json:"MsgId"`
  64. }
  65. // EventTemplateReply event reply
  66. type EventTemplateReply struct {
  67. XMLName xml.Name `xml:"xml"`
  68. ToUserName string `xml:"ToUserName"`
  69. FromUserName string `xml:"FromUserName"`
  70. CreateTime string `xml:"CreateTime"`
  71. MsgType string `xml:"MsgType"`
  72. Event string `xml:"Event"`
  73. MsgID string `xml:"MsgID"`
  74. Status string `xml:"Status"`
  75. }
  76. var (
  77. cache sync.Map
  78. )
  79. // Sign 微信计算签名的函数
  80. func Sign(req map[string]interface{}, key string) (sign string) {
  81. keys := make([]string, 0)
  82. for k := range req {
  83. keys = append(keys, k)
  84. }
  85. sort.Strings(keys)
  86. var s string
  87. for _, k := range keys {
  88. value := fmt.Sprintf("%v", req[k])
  89. if value != "" {
  90. s = s + k + "=" + value + "&"
  91. }
  92. }
  93. if key != "" {
  94. s = s + "key=" + key
  95. }
  96. sign = strings.ToUpper(util.MD5(s))
  97. return
  98. }
  99. func makeSignature(token, signature, timestamp, nonce string) bool {
  100. sl := []string{token, timestamp, nonce}
  101. sort.Strings(sl)
  102. return strings.Compare(signature, util.SHA1(strings.Join(sl, ""))) == 0
  103. }
  104. func checkErrorWithBody(msg util.Message) (body []byte, err error) {
  105. if msg.StatusCode == 200 {
  106. var res ResponseMsg
  107. err = json.Unmarshal(msg.Body, &res)
  108. if err == nil {
  109. if res.ErrCode != 0 {
  110. err = errors.New(res.ErrMsg)
  111. } else {
  112. body = msg.Body
  113. }
  114. }
  115. } else {
  116. err = errors.New(`HTTP StatusCode not 200`)
  117. }
  118. return
  119. }
  120. func checkError(msg util.Message) (res Response, err error) {
  121. if msg.StatusCode == 200 {
  122. err = json.Unmarshal(msg.Body, &res)
  123. if err == nil {
  124. if res.ErrCode != 0 {
  125. err = errors.New(res.ErrMsg)
  126. }
  127. }
  128. } else {
  129. err = errors.New(`HTTP StatusCode not 200`)
  130. }
  131. return
  132. }
  133. func getJSON(uri string) (res Response, err error) {
  134. var msg util.Message
  135. if msg, err = util.Get(uri, map[string]string{}); err != nil {
  136. return
  137. }
  138. res, err = checkError(msg)
  139. return
  140. }
  141. func getBody(uri string) (body []byte, err error) {
  142. var msg util.Message
  143. if msg, err = util.Get(uri, map[string]string{}); err != nil {
  144. return
  145. }
  146. body, err = checkErrorWithBody(msg)
  147. return
  148. }
  149. func postXML(url string, data []byte) (res Response, err error) {
  150. var (
  151. msg util.Message
  152. headers = make(map[string]string)
  153. )
  154. headers["Accept"] = "application/json"
  155. headers["Content-Type"] = "application/xml; charset=utf-8"
  156. msg, err = util.Post(url, headers, bytes.NewReader(data))
  157. if err != nil {
  158. return
  159. }
  160. res, err = checkError(msg)
  161. return
  162. }
  163. func postJSON(url string, data []byte) (res Response, err error) {
  164. var (
  165. msg util.Message
  166. headers = make(map[string]string)
  167. )
  168. headers["Accept"] = "application/json"
  169. headers["Content-Type"] = "application/json; charset=utf-8"
  170. msg, err = util.Post(url, headers, bytes.NewReader(data))
  171. if err != nil {
  172. return
  173. }
  174. res, err = checkError(msg)
  175. return
  176. }
  177. func postBody(uri string, data []byte) (body []byte, err error) {
  178. var (
  179. msg util.Message
  180. headers = make(map[string]string)
  181. )
  182. headers["Accept"] = "application/json"
  183. headers["Content-Type"] = "application/json; charset=utf-8"
  184. msg, err = util.Post(uri, headers, bytes.NewReader(data))
  185. if err != nil {
  186. return
  187. }
  188. body, err = checkErrorWithBody(msg)
  189. return
  190. }