使用golang快速开发微信公众平台(二):获取accessToken

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012210379/article/details/52795296

微信的文档有个很有意思的地方,刚开始你顺着文档看,就可以一步一步完成自己需要的功能,但走着走着,就感到有些混乱,你再顺着文档做,就掉坑里了。

我们在使用golang快速开发微信公众平台(一)微信验证服务器通过后,就要开始着手获取accessToken,这个东西很重要,在菜单、客服、支付等操作中都需要用到


在文档中,有以下2点很重要:

  1. access_token每日限额获取2000次,相当于允许你以43秒的频率来取,但明显这样做会显得很傻。
  2. access_token有效时间是7200秒

这里写图片描述
以get请求获取一段json并解析来获取access_token,看起来很简单对不对?但应用到实际中就稍微有些麻烦了:

  1. 需要找个什么东西来存,可以是文件、可以是数据库、甚至可以直接就扔到全局变量里。嗯,我选数据库。
  2. 定时发送这个get请求,更新数据库。
  3. 这个get请求是可能失败的 是可能失败的 是可能失败的,虽然这个概率极低,但对于如此重要的参数,一旦在2个小时的空档期内都无法调用,会产生极其灾难性的后果,别问我怎么知道的

好,思路捋一下,3件事:拼接get请求json解析,建个表来存取更新,定时任务

开始搓代码

access_token的存取

WxAccTokenUtil.go

package WxPlatUtil

import (
    "strings"
    "net/http"
    "fmt"
    "io/ioutil"
    "bytes"
    "encoding/json"
    "mlshop/shopUtils/logUtils"
    "mlshop/models"
)

type AccessTokenResponse struct {
    AccessToken string  `json:"access_token"`
    ExpiresIn   float64 `json:"expires_in"`
}

//type AccessTokenErrorResponse struct {
//  Errcode float64
//  Errmsg  string
//}
//获取wx_AccessToken 拼接get请求 解析返回json结果 返回 AccessToken和err
func FetchAccessToken(appID, appSecret, accessTokenFetchUrl string) (string, error) {

    requestLine := strings.Join([]string{accessTokenFetchUrl,
        "?grant_type=client_credential&appid=",
        appID,
        "&secret=",
        appSecret}, "")

    resp, err := http.Get(requestLine)
    if err != nil || resp.StatusCode != http.StatusOK {
        fmt.Println("发送get请求获取 atoken 错误", err)
        logUtils.GetLog().Error("发送get请求获取 atoken 错误", err)
        return "", err
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("发送get请求获取 atoken 读取返回body错误", err)
        logUtils.GetLog().Error("发送get请求获取 atoken 读取返回body错误", err)
        return "", err
    }

    if bytes.Contains(body, []byte("access_token")) {
        atr := AccessTokenResponse{}
        err = json.Unmarshal(body, &atr)
        if err != nil {
            fmt.Println("发送get请求获取 atoken 返回数据json解析错误", err)
            logUtils.GetLog().Error("发送get请求获取 atoken 返回数据json解析错误", err)
            return "", err
        }
        return atr.AccessToken, atr.ExpiresIn, nil
    } else {
        fmt.Println("发送get请求获取 微信返回 err")
        ater := models.AccessTokenErrorResponse{}
        err = json.Unmarshal(body, &ater)
        fmt.Printf("发送get请求获取 微信返回 的错误信息 %+v\n", ater)
        if err != nil {
            return "", err
        }
        return "", fmt.Errorf("%s", ater.Errmsg)
    }
}
//type WxAccessToken struct {
//  Id          int `orm:"auto"`
//  AccessToken string
//}
//微信公众平台的参数
//type WxBase struct {
//  Id             int `orm:"auto"`
//  AppID          string
//  AppSecret      string
//  Token          string
//  EncodingAESKey string
//}
//数据库存取更新access_token
func GetAndUpdateDBWxAToken(o orm.Ormer) error {

    at := models.WxAccessToken{Id: 1}
    o.ReadOrCreate(&at, "id")

    wxBase := models.WxBase{Id:1}
    err := orm.NewOrm().Read(&wxBase)
    if err != nil {
        fmt.Println("从数据库查询WxBase失败", err)
        return err
    }

    //向微信服务器发送获取accessToken的get请求
    accessToken, err := WxPlatUtil.FetchAccessToken(wxBase.AppID, wxBase.AppSecret, "https://api.weixin.qq.com/cgi-bin/token")
    if err != nil {
        fmt.Println("向微信服务器发送获取accessToken的get请求失败", err)
        logUtils.GetLog().Error("向微信服务器发送获取accessToken的get请求失败", err)
        return err
    }

    at.AccessToken = accessToken
    o.Update(&at, "access_token")

    return nil
}

得益于go语言方便的json与struct转换和beego的orm,第一个任务很快就可以完成。
接下来,我们要考虑定时任务的问题。

定时任务

定时的话time包倒是有个ticker,出现在脑子里的第一个思路是把时间段时间点都转化为秒数,然后开始倒计时。。。好傻
可以搜到很多关于golang的time使用方法,比如下面这个

 func startTimer(f func()) {
        go func() {
            for {
                f()
                now := time.Now()
                // 计算下一个零点
                next := now.Add(time.Hour * 24)
                next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location())
                t := time.NewTimer(next.Sub(now))
                <-t.C
            }
        }()
    }

嗯 看起来还是很不错的,群里讨论的时候,大家都喜欢在当前时间上+24小时获取明天,然后取0点,然后加上自己想要的时间段

但是 GRD的需求是会变来变去的

今天要求是明天2点,后天要求是明天2点半,大后天又变成了9个小时来一次。结合咱们的定时任务,要是既能传时间段,又能传时间点就好了。
这里写图片描述

github上go的time库倒是有,可我一个都没用到。嗯 因为懒。

这里写图片描述

这就是为啥我推荐大家用pycharm、phpstrom、webstrom来写go,看库多方便,而且还自带ssh ftp工具,是人都知道在Win Mac 上找不同的ftp工具是多么的痛苦。表用IDEA…等你用了就知道为啥。

beego自带的定时任务模块很强,而且使用简单,虽然传参很丑,不适合装逼,丑到啥地步呢:

这里写图片描述

如果是集团军作战,传这样的参数肯定是被骂的,但咱是单兵作战,好用即可。到这里,咱们的定时任务也可以出炉了:

//从task_test.go文件里找使用方法
func shopTimeTask(o orm.Ormer) {

    timeStr2 := "0 */60 * * * *" // 获取wx token
    t2 := toolbox.NewTask("getAtoken", timeStr2, func() error {

         err := WxPlatUtil.GetAndUpdateDBWxAToken(o)
         if err != nil{
            //todo 向微信请求access_token失败 结合业务逻辑处理
        }
         return nil
    })
    toolbox.AddTask("tk2", t2)
    toolbox.StartTask()

}

唉咋知道怎么用的?test文件啊;唉这命名真不规范,我还有数据库备份也用代码写的。。。
ok,就这么几句,23步咱们都干完了,第三步其实大家自行处理就好。虽然说的很严重,但是只要有处理就不会那么惨。。。

展开阅读全文

没有更多推荐了,返回首页