wechat_client.go 3.3 KB

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