Skip to content

Go对接三方API实践

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

前言

本月会持续更新Go语言相关的文章,尤其是GoFrame,感兴趣的同学可以关注我,结伴而行。

同时会沉淀总结一下:《中台开发实践》、《私有化部署实践》、《深入理解goroutine及使用实践》、《如何在开发过程中把GO语言的价值体现出来》。

立志沉淀一些质量高的内容出来。

今天这篇分享:使用Go语言对接三方API实践。

知识点分析

  1. 网络请求
  2. 缓存
  3. 获得token
  4. 刷新token
  5. redis的使用

关键代码

定义结构体

关键点

  1. 能复用的一定要复用
  2. 能分层的一定要分层
go

```type Config struct {    ApiUrl    string    AppKey    string    AppSecret string    Version   string } type Client struct {    *Config    AccessToken  string    RefreshToken string } type CommonReq struct {    AppKey      string      `json:"app_key"`    Version     string      `json:"version"`    Method      string      `json:"method"`    AccessToken string      `json:"access_token"`    Timestamp   string      `json:"timestamp"`    Param       interface{} `json:"param"`    Sign        string      `json:"sign,omitempty"` } type CommonPageReq struct {    PageNo   int `json:"pageNo"`    PageSize int `json:"pageSize"` } type CommonPageRes struct {    PageSize   int `json:"pageSize"`    PageNo     int `json:"pageNo"`    TotalPage  int `json:"totalPage"`    TotalCount int `json:"totalCount"` } type CommonRes struct {    Code    string `json:"code"`    Message string `json:"message"`    SubCode string `json:"sub_code"`    SubMsg  string `json:"sub_msg"` }``

## 签名相关

1.  根据三方要求进行签名(验签)
2.  比如我这里示例的:md5加密

``` go
func (s *Client) sign(req g.Map) string {    data := gjson.New(req)    _ = data.Remove("sign")    return gstr.ToUpper(gmd5.MustEncryptString(server.AppSecret + data.MustToJsonString() + server.AppSecret)) }

封装请求

go
func (s *Client) post(ctx context.Context, method string, req interface{}) (str string, err error) {    Start := gtime.TimestampMilli()    allparams := &CommonReq{       AppKey:      server.AppKey,       Version:     server.Version,       Method:      method,       AccessToken: server.AccessToken,       Timestamp:   gtime.Now().String(),       Param:       req,    }    allparams.Sign = s.sign(gconv.Map(allparams))    Request := g.Client()    Request.SetHeader("Content-Type", "application/json")    resp, err := Request.Timeout(time.Second*5).Post(server.ApiUrl, allparams)    defer func() {       paramStr := gjson.New(req).MustToJsonString()       ctx = context.WithValue(ctx, "Method", "POST")       ctx = context.WithValue(ctx, "URI", method)       if err != nil {          logs.Errorf(ctx, pkgName, logs.FormatErr, paramStr, err.Error(), gtime.TimestampMilli()-Start)       } else {          logs.Infof(ctx, pkgName, logs.FormatSuc, paramStr, str, gtime.TimestampMilli()-Start)       }    }()    str = resp.ReadAllString()    return } func (s *Client) requestApi(ctx context.Context, method string, req interface{}) (str string, err error) {    err = s.getAccessToken(ctx)    if err != nil {       return    }    str, err = s.post(ctx, method, req)    return }

管理token

  1. 注意看redis的使用
  2. token一般都是有有效期的,token应该缓存起来,不应该每次都请求获得新的token
  3. 刷新token一般有两种方式:一种是刷新token的有效期,一种是在有效期内使用旧token获得新token
go

```type accessToken struct {    AppKey           string `json:"appKey"`    AccessToken      string `json:"access_token"`    RefreshToken     string `json:"refresh_token"`    ExpiresInSeconds int64  `json:"expiresInSeconds"`    CreateTime       string `json:"createTime"` } //getAccessToken 获取token func (s *Client) getAccessToken(ctx context.Context) (err error) {    var token *accessToken    cache, _ := g.Redis().DoVar("HGETALL", CacheKey)    if !cache.IsEmpty() {       _ = cache.Scan(&token)       if gtime.NewFromStr(token.CreateTime).Timestamp()+token.ExpiresInSeconds > gtime.Timestamp()-3600 {          s.AccessToken = token.AccessToken          return       }       return s.refreshToken(ctx, token)    }    res, err := Token.Get(ctx)    if err != nil {       return    }    if res.Code != "4000" {       err = errors.New(res.Message)       return    }    _, err = g.Redis().Do("HMSET", append(g.Slice{CacheKey}, gutil.MapToSlice(gconv.Map(res.Data))...)...)    if err != nil {       logs.Errorf(ctx, pkgName, logs.FormatErr, err.Error())    }    s.AccessToken = res.Data.AccessToken    return } //refreshToken 刷新token func (s *Client) refreshToken(ctx context.Context, req *accessToken) (err error) {    if gtime.NewFromStr(req.CreateTime).Timestamp()+req.ExpiresInSeconds < gtime.Timestamp() {       _, err = g.Redis().DoVar("DEL", CacheKey)       return s.getAccessToken(ctx)    }    res, err := Token.Refresh(ctx, req.RefreshToken)    if err != nil {       return    }    if res.Code != "4000" {       err = errors.New(res.Message)       return    }    _, _ = g.Redis().Do("HMSET", append(g.Slice{CacheKey}, gutil.MapToSlice(gconv.Map(res.Data))...)...)    s.AccessToken = res.Data.AccessToken    return }``

# 总结

这篇总结了比较典型的使用Go语言对接三方API请求token、刷新token、封装请求、使用Redis缓存token的实践。

整体思路比较清晰,尤其是Redis的使用部分,使用了GoFrame框架的常用函数。

对GO感兴趣的朋友可以查看我之前写的文章,了解一下Go的魅力:

[Go语言为什么值得学习?](https://juejin.cn/post/7064778754979004447 "https://juejin.cn/post/7064778754979004447")

[我的PHP转Go之旅](https://juejin.cn/post/6976059413966618638 "https://juejin.cn/post/6976059413966618638")

[回顾一下我的Go学习之旅](https://juejin.cn/post/6949109361331568670 "https://juejin.cn/post/6949109361331568670")

[非常适合PHP和Java转Go学习的框架:GoFrame](https://juejin.cn/post/7075098594151235597 "https://juejin.cn/post/7075098594151235597")

欢迎大家关注我的`Go语言学习专栏`,我会持续更新在Go学习和使用过程中的干货分享。

[Go语言学习专栏](https://juejin.cn/column/7064777730532835336 "https://juejin.cn/column/7064777730532835336")

# 最后

**感谢阅读,欢迎大家三连:点赞、收藏、投币(关注)!!!**

![8e95dac1fd0b2b1ff51c08757667c47a.gif](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c92c98dc810d47b18f07ac141e38bf4c~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)

🚀 学习遇到瓶颈?想进大厂?

看完这篇技术文章,如果还是觉得不够系统,或者想在实战中快速提升?
王中阳的就业陪跑训练营,提供定制化学习路线 + 企业级实战项目 + 简历优化 + 模拟面试。

了解训练营详情