123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package service
- import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "strings"
- "time"
- "youngee_b_api/consts"
- "youngee_b_api/model/http_model"
- "youngee_b_api/model/system_model"
- "youngee_b_api/redis"
- )
- const (
- accessTokenUrlFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
- qrCodeUrlFormat = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
- wxAccesssTokenKey = "wx_access_token"
- )
- var QrCode *qrcode
- type qrcode struct {
- sessionTTL time.Duration
- }
- func QrCodeInit(config *system_model.Session) {
- qrCode := new(qrcode)
- qrCode.sessionTTL = 5 * time.Minute
- QrCode = qrCode
- }
- // getAndCacheWxAccessToken 获取并缓存微信的access token
- func getAndCacheWxAccessToken(ctx context.Context) (string, error) {
- appId := "wxac396a3be7a16844"
- secret := "c82ae9e75b4ed7d8022db5bda5371892"
- url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
- resp, err := http.Get(url)
- if err != nil {
- return "", errors.New("request access token failed")
- }
- defer resp.Body.Close()
- // 解析微信服务端返回的信息
- var accessTokenRes http_model.WxAccessTokenResponse
- decoder := json.NewDecoder(resp.Body)
- if err = decoder.Decode(&accessTokenRes); err != nil {
- return "", errors.New("decode wx response failed")
- }
- if accessTokenRes.Errcode != 0 {
- return "", errors.New("request access token failed")
- }
- // 缓存获取的access token,比微信返回的有效时间短5分钟失效
- err = redis.Set(ctx, wxAccesssTokenKey, accessTokenRes.AccessToken, QrCode.sessionTTL)
- if err != nil {
- return "", err
- }
- return accessTokenRes.AccessToken, nil
- }
- func (q *qrcode) GetWxQrCode(ctx context.Context, Scene string, Page string) (*http_model.GetWxQRCodeData, error) {
- // 获取access_token
- accessToken, err := redis.Get(ctx, wxAccesssTokenKey)
- if err != nil && err != consts.RedisNil {
- fmt.Printf("err: %+v\n", err)
- return nil, err
- }
- if accessToken == "" {
- // 如果没有缓存的access token 则获取并缓存
- accessToken, err = getAndCacheWxAccessToken(ctx)
- if err != nil {
- fmt.Printf("err: %+v\n", err)
- return nil, err
- }
- }
- qrRequest := http_model.WxQrCodeRequest{
- Scene: Scene,
- Page: Page,
- Width: 430,
- CheckPath: false,
- EnvVersion: "release",
- }
- jsonBody, err := json.Marshal(qrRequest)
- if err != nil {
- fmt.Printf("err: %+v\n", err)
- return nil, err
- }
- qrCodeUrl := fmt.Sprintf(qrCodeUrlFormat, accessToken)
- resp, err := http.Post(qrCodeUrl, "application/json; charset=utf8", bytes.NewReader(jsonBody))
- if err != nil {
- fmt.Printf("err: %+v\n", err)
- return nil, err
- }
- defer resp.Body.Close()
- var qrcodeBytes []byte
- switch header := resp.Header.Get("content-Type"); {
- case strings.HasPrefix(header, "application/json"):
- // 如果返回的是json结构,说明发生错误
- var qrResponse *http_model.WxQrCodeResponse
- decoder := json.NewDecoder(resp.Body)
- if err = decoder.Decode(&qrResponse); err != nil {
- fmt.Printf("decoder: %+v\nerr: %+v", decoder, err)
- return nil, err
- }
- fmt.Printf("qrResponse: %+v\ndecoder: %+v\n", qrResponse, decoder)
- return nil, nil
- case strings.HasPrefix(header, "image"):
- qrcodeBytes, err = ioutil.ReadAll(resp.Body)
- if err != nil {
- fmt.Printf("qrcodeBytes: %+v\nerr: %+v", qrcodeBytes, err)
- return nil, err
- }
- }
- data := http_model.GetWxQRCodeData{
- QrCodeBytes: qrcodeBytes,
- }
- //fmt.Printf("data: %+v\n", data)
- return &data, nil
- }
|