wechat_client.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package wechat
  2. import (
  3. "encoding/json"
  4. "eta/eta_mini_ht_api/common/component/config"
  5. logger "eta/eta_mini_ht_api/common/component/log"
  6. "eta/eta_mini_ht_api/common/component/wechat/we_http"
  7. "eta/eta_mini_ht_api/common/contants"
  8. "eta/eta_mini_ht_api/common/exception"
  9. "eta/eta_mini_ht_api/common/utils/client"
  10. "fmt"
  11. "io"
  12. "net/url"
  13. "sync"
  14. )
  15. const (
  16. baseURL = "https://api.weixin.qq.com"
  17. codeAPI = "/sns/jscode2session"
  18. )
  19. const (
  20. // WeChatServerError 微信服务器错误时返回返回消息
  21. )
  22. var (
  23. wechatClient *Client
  24. once sync.Once
  25. )
  26. type Client struct {
  27. // HTTP请求客户端
  28. client *client.HttpClient
  29. // 小程序后台配置: 小程序ID
  30. appid string
  31. // 小程序后台配置: 小程序密钥
  32. secret string
  33. }
  34. func GetInstance() *Client {
  35. once.Do(func() {
  36. wechatConf, ok := config.GetConfig(contants.WECHAT).(*config.WechatConfig)
  37. if !ok {
  38. // 处理错误情况,比如记录日志或返回错误信息
  39. logger.Info("加载wechat配置失败")
  40. return // 或者采取其他适当的错误处理措施
  41. }
  42. // 默认配置
  43. wechatClient = NewClient(wechatConf.GetAppid(), wechatConf.GetSecret(), WithHttpClient(client.DefaultClient()))
  44. })
  45. return wechatClient
  46. }
  47. // AccessTokenGetter 用户自定义获取access_token的方法
  48. type AccessTokenGetter func(appid, secret string) (token string, expireIn uint)
  49. // NewClient 初始化客户端并用自定义配置替换默认配置
  50. func NewClient(appid, secret string, opts ...func(*Client)) *Client {
  51. cli := &Client{
  52. appid: appid,
  53. secret: secret,
  54. }
  55. // 执行额外的配置函数
  56. for _, fn := range opts {
  57. fn(cli)
  58. }
  59. return cli
  60. }
  61. // WithHttpClient 自定义 HTTP Client
  62. func WithHttpClient(hc *client.HttpClient) func(*Client) {
  63. return func(cli *Client) {
  64. cli.client = hc
  65. }
  66. }
  67. type loginResponse struct {
  68. we_http.BaseResponse
  69. we_http.LoginResponse
  70. }
  71. // Login 小程序登录
  72. func (cli *Client) Login(code string) (wxUser WxUser, err error) {
  73. if code == "" {
  74. err = exception.New(exception.WeChatCodeEmpty)
  75. return
  76. }
  77. api, err := code2url(cli.appid, cli.secret, code)
  78. if err != nil {
  79. err = exception.New(exception.WeChatIllegalRequest)
  80. return
  81. }
  82. //请求微信接口
  83. res, err := cli.client.Get(api)
  84. if err != nil || res.StatusCode != 200 {
  85. if res != nil {
  86. logger.Error("获取微信用户信息失败:%v", res.Status)
  87. } else {
  88. logger.Error("获取微信用户信息失败:%v", err)
  89. }
  90. err = exception.New(exception.WeChatServerError)
  91. return
  92. }
  93. defer func(Body io.ReadCloser) {
  94. Body.Close()
  95. }(res.Body)
  96. var data loginResponse
  97. err = json.NewDecoder(res.Body).Decode(&data)
  98. if err != nil {
  99. logger.Error("解析微信应答失败:%v", err)
  100. err = exception.New(exception.WeChatResponseError)
  101. return
  102. }
  103. if data.Errcode != 0 {
  104. logger.Error("获取用户信息失败:%v", data.Errmsg)
  105. err = exception.New(exception.WechatUserInfoFailed)
  106. return
  107. }
  108. wxUser = WxUser{
  109. OpenId: data.LoginResponse.OpenID,
  110. UnionId: data.LoginResponse.UnionID,
  111. }
  112. return
  113. }
  114. type WxUser struct {
  115. OpenId string
  116. UnionId string
  117. }
  118. // 拼接 获取 session_key 的 URL
  119. func code2url(appID, secret, code string) (string, error) {
  120. url, err := url.Parse(baseURL + codeAPI)
  121. if err != nil {
  122. return "", err
  123. }
  124. query := url.Query()
  125. query.Set("appid", appID)
  126. query.Set("secret", secret)
  127. query.Set("js_code", code)
  128. query.Set("grant_type", "authorization_code")
  129. url.RawQuery = query.Encode()
  130. return url.String(), nil
  131. }
  132. type WxUserInfo struct {
  133. OpenId string `json:"openid"`
  134. AccessToken string `json:"access_token"`
  135. RefreshToken string `json:"refresh_token"`
  136. Scope string `json:"scope"`
  137. ErrCode int
  138. ErrMsg string
  139. }
  140. // Login 小程序登录
  141. func (cli *Client) GzhLogin(code string) (wxUser WxUser, err error) {
  142. if code == "" {
  143. err = exception.New(exception.WeChatCodeEmpty)
  144. return
  145. }
  146. api, err := code2url(cli.appid, cli.secret, code)
  147. if err != nil {
  148. err = exception.New(exception.WeChatIllegalRequest)
  149. return
  150. }
  151. //请求微信接口
  152. res, err := cli.client.Get(api)
  153. defer func(Body io.ReadCloser) {
  154. Body.Close()
  155. }(res.Body)
  156. if err != nil || res.StatusCode != 200 {
  157. logger.Error("获取微信用户信息失败:%v", res.Status)
  158. err = exception.New(exception.WeChatServerError)
  159. return
  160. }
  161. var data loginResponse
  162. err = json.NewDecoder(res.Body).Decode(&data)
  163. if err != nil {
  164. logger.Error("解析微信应答失败:%v", err)
  165. err = exception.New(exception.WeChatResponseError)
  166. return
  167. }
  168. fmt.Println(data)
  169. if data.Errcode != 0 {
  170. logger.Error("获取用户信息失败:%v", data.Errmsg)
  171. err = exception.New(exception.WechatUserInfoFailed)
  172. return
  173. }
  174. wxUser = WxUser{
  175. OpenId: data.LoginResponse.OpenID,
  176. UnionId: data.LoginResponse.UnionID,
  177. }
  178. return
  179. }