qrcode.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io/ioutil"
  9. "net/http"
  10. "strings"
  11. "time"
  12. "youngee_b_api/consts"
  13. "youngee_b_api/model/http_model"
  14. "youngee_b_api/model/system_model"
  15. "youngee_b_api/redis"
  16. )
  17. const (
  18. accessTokenUrlFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
  19. qrCodeUrlFormat = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
  20. wxAccesssTokenKey = "wx_access_token"
  21. )
  22. var QrCode *qrcode
  23. type qrcode struct {
  24. sessionTTL time.Duration
  25. }
  26. func QrCodeInit(config *system_model.Session) {
  27. qrCode := new(qrcode)
  28. qrCode.sessionTTL = 5 * time.Minute
  29. QrCode = qrCode
  30. }
  31. // getAndCacheWxAccessToken 获取并缓存微信的access token
  32. func getAndCacheWxAccessToken(ctx context.Context) (string, error) {
  33. appId := "wxac396a3be7a16844"
  34. //secret := "c82ae9e75b4ed7d8022db5bda5371892"
  35. secret := "abbf27d46c46212c86e60f2ed3c534ee"
  36. url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
  37. resp, err := http.Get(url)
  38. if err != nil {
  39. return "", errors.New("request access token failed")
  40. }
  41. defer resp.Body.Close()
  42. // 解析微信服务端返回的信息
  43. var accessTokenRes http_model.WxAccessTokenResponse
  44. decoder := json.NewDecoder(resp.Body)
  45. if err = decoder.Decode(&accessTokenRes); err != nil {
  46. return "", errors.New("decode wx response failed")
  47. }
  48. if accessTokenRes.Errcode != 0 {
  49. return "", errors.New("request access token failed")
  50. }
  51. // 缓存获取的access token,比微信返回的有效时间短5分钟失效
  52. err = redis.Set(ctx, wxAccesssTokenKey, accessTokenRes.AccessToken, QrCode.sessionTTL)
  53. if err != nil {
  54. return "", err
  55. }
  56. return accessTokenRes.AccessToken, nil
  57. }
  58. func (q *qrcode) GetWxQrCode(ctx context.Context, Scene string, Page string) (*http_model.GetWxQRCodeData, error) {
  59. // 获取access_token
  60. accessToken, err := redis.Get(ctx, wxAccesssTokenKey)
  61. if err != nil && err != consts.RedisNil {
  62. fmt.Printf("err: %+v\n", err)
  63. return nil, err
  64. }
  65. if accessToken == "" {
  66. // 如果没有缓存的access token 则获取并缓存
  67. accessToken, err = getAndCacheWxAccessToken(ctx)
  68. if err != nil {
  69. fmt.Printf("err: %+v\n", err)
  70. return nil, err
  71. }
  72. }
  73. qrRequest := http_model.WxQrCodeRequest{
  74. Scene: Scene,
  75. Page: Page,
  76. Width: 150,
  77. CheckPath: false,
  78. EnvVersion: "release",
  79. }
  80. jsonBody, err := json.Marshal(qrRequest)
  81. if err != nil {
  82. fmt.Printf("err: %+v\n", err)
  83. return nil, err
  84. }
  85. qrCodeUrl := fmt.Sprintf(qrCodeUrlFormat, accessToken)
  86. resp, err := http.Post(qrCodeUrl, "application/json; charset=utf8", bytes.NewReader(jsonBody))
  87. if err != nil {
  88. fmt.Printf("err: %+v\n", err)
  89. return nil, err
  90. }
  91. defer resp.Body.Close()
  92. var qrcodeBytes []byte
  93. switch header := resp.Header.Get("content-Type"); {
  94. case strings.HasPrefix(header, "application/json"):
  95. // 如果返回的是json结构,说明发生错误
  96. var qrResponse *http_model.WxQrCodeResponse
  97. decoder := json.NewDecoder(resp.Body)
  98. if err = decoder.Decode(&qrResponse); err != nil {
  99. fmt.Printf("decoder: %+v\nerr: %+v", decoder, err)
  100. return nil, err
  101. }
  102. fmt.Printf("qrResponse: %+v\ndecoder: %+v\n", qrResponse, decoder)
  103. return nil, nil
  104. case strings.HasPrefix(header, "image"):
  105. qrcodeBytes, err = ioutil.ReadAll(resp.Body)
  106. if err != nil {
  107. fmt.Printf("qrcodeBytes: %+v\nerr: %+v", qrcodeBytes, err)
  108. return nil, err
  109. }
  110. }
  111. data := http_model.GetWxQRCodeData{
  112. QrCodeBytes: qrcodeBytes,
  113. }
  114. //fmt.Printf("data: %+v\n", data)
  115. return &data, nil
  116. }