wechat.go 5.3 KB

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