wechat_client.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. defer func(Body io.ReadCloser) {
  85. Body.Close()
  86. }(res.Body)
  87. if err != nil || res.StatusCode != 200 {
  88. logger.Error("获取微信用户信息失败:%v", res.Status)
  89. err = exception.New(exception.WeChatServerError)
  90. return
  91. }
  92. var data loginResponse
  93. err = json.NewDecoder(res.Body).Decode(&data)
  94. if err != nil {
  95. logger.Error("解析微信应答失败:%v", err)
  96. err = exception.New(exception.WeChatResponseError)
  97. return
  98. }
  99. fmt.Println(data)
  100. if data.Errcode != 0 {
  101. logger.Error("获取用户信息失败:%v", data.Errmsg)
  102. err = exception.New(exception.WechatUserInfoFailed)
  103. return
  104. }
  105. wxUser = WxUser{
  106. OpenId: data.LoginResponse.OpenID,
  107. UnionId: data.LoginResponse.UnionID,
  108. }
  109. return
  110. }
  111. type WxUser struct {
  112. OpenId string
  113. UnionId string
  114. }
  115. // 拼接 获取 session_key 的 URL
  116. func code2url(appID, secret, code string) (string, error) {
  117. url, err := url.Parse(baseURL + codeAPI)
  118. if err != nil {
  119. return "", err
  120. }
  121. query := url.Query()
  122. query.Set("appid", appID)
  123. query.Set("secret", secret)
  124. query.Set("js_code", code)
  125. query.Set("grant_type", "authorization_code")
  126. url.RawQuery = query.Encode()
  127. return url.String(), nil
  128. }