您的位置:首页 > 科技 > 能源 > 深圳著名设计公司_网站每天做100个外链_女生seo专员很难吗为什么_可以放友情链接的网站

深圳著名设计公司_网站每天做100个外链_女生seo专员很难吗为什么_可以放友情链接的网站

2024/12/27 17:46:52 来源:https://blog.csdn.net/rxbook/article/details/143004503  浏览:    关键词:深圳著名设计公司_网站每天做100个外链_女生seo专员很难吗为什么_可以放友情链接的网站
深圳著名设计公司_网站每天做100个外链_女生seo专员很难吗为什么_可以放友情链接的网站

文章目录

  • 获取企业微信用户id
    • 发送HTTP的GET和POST请求的方法
    • 实现方法和调试
  • 获取企业微信access_token
    • 使用 Redis 将 access_token缓存起来
  • 代码优化
    • 代码逻辑拆分service层和controller层
    • 参数改为由客户端传递
    • 企微配置文件初始化

这篇文章主要是讲一下在Go语言Gin框架中对接企业微信获取数据的一个代码示例,主要涉及到Redis的基本用法、HTTP的GET和POST请求、对接企业微信接口获取数据并返回JSON。

获取企业微信用户id

拿到需求,首先第一感觉就是查找企业微信(以下简称“企微”)的文档,文档链接如下:https://developer.work.weixin.qq.com/document/path/95402

请求方式:POST(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN
请求包体:
{"mobile": "13430388888"
}

OK, 拿到了接口文档,那么下一步就是要发送一个HTTP请求了。

发送HTTP的GET和POST请求的方法

我们先来封装一个发送HTTP的GET和POST请求的方法,这类方法网上一查就能搜到一大堆,也不需要死记硬背,实在不行问一下AI也行:

//utils/funcUtils/http.gopackage funcUtilsimport ("bytes""encoding/json""fmt""io/ioutil""net/http""time"
)// HttpGet 发送GET请求
// url:请求地址
func HttpGet(url string) (map[string]interface{}, error) {client := &http.Client{Timeout: 5 * time.Second}fmt.Println("HttpGet请求三方接口信息:", url)resp, err := client.Get(url)if err != nil {fmt.Println("HttpGet调用三方接口出现了错误:", err)return nil, err}res, err := ioutil.ReadAll(resp.Body)fmt.Println("HttpGet三方接口返回信息:", bytes.NewBuffer(res), err)// 将 JSON 字符串转换为 map[string]interface{}var dataMap map[string]interface{}if err := json.Unmarshal([]byte(res), &dataMap); err != nil {fmt.Printf("Failed to unmarshal JSON: %v\n", err)return nil, err}return dataMap, nil
}// HttpPost 发送POST请求
// url:         请求地址
// data:        POST请求提交的数据
// contentType: 请求体格式,如:application/json
func HttpPost(url string, data interface{}, contentType string) (map[string]interface{}, error) {//创建调用API接口的clientclient := &http.Client{Timeout: 5 * time.Second}jsonStr, _ := json.Marshal(data)fmt.Println("HttpPost请求三方接口信息:", url, bytes.NewBuffer(jsonStr))resp, err := client.Post(url, contentType, bytes.NewBuffer(jsonStr))if err != nil {fmt.Println("HttpPost调用三方接口出现了错误:", err)return nil, err}res, err := ioutil.ReadAll(resp.Body)fmt.Println("HttpPost三方接口返回信息:", bytes.NewBuffer(res), err)// 将 JSON 字符串转换为 map[string]interface{}var dataMap map[string]interface{}if err := json.Unmarshal([]byte(res), &dataMap); err != nil {fmt.Printf("Failed to unmarshal JSON: %v\n", err)return nil, err}return dataMap, err
}

实现方法和调试

接下来,新增一个controller文件,开始写实现方法:

// controllers/userController/user.go// 获取企业微信用户详情
func GetWorkWechatUserInfo(c *gin.Context) {var weworkRequestParams = map[string]string{"mobile": "132xxxxx", //传入一个手机号}workWechatAccessTokenVal := "xxxx" //企微accessToken,可以先写死url := "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=" + workWechatAccessTokenValdata, err := funcUtils.HttpPost(url, weworkRequestParams, "application/json")fmt.Println(data)fmt.Println(err)
}

上面的代码逻辑很简单,定义好需要发送POST请求的URL和参数body体,其中 access_token 先不管,先随便传一个字符串试试POST请求能不能通。

然后,定义一个路由:

// router/user.gopackage routerfunc UserRouter(e *gin.Engine) {user := e.Group("/user"){user.POST("/workWechatUserInfo", userController.GetWorkWechatUserInfo)}
}

运行一下,启动后用 postman 发送 POST请求访问 http://127.0.0.1:8080/user/workWechatUserInfo 看看控制台输出:
在这里插入图片描述

企微返回了一个json数据,说明我们的POST请求发送成功了。接下来,按照企微返回的提示信息,我们来获取一下 access_token。

获取企业微信access_token

同样的,找到企微的文档如下:https://developer.work.weixin.qq.com/document/path/91039

请求方式: GET(HTTPS)
请求地址: https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET

这次是个 GET请求,刚好上面我们已经把GET请求的方法封装好了,直接调用就行。这里需要传两个参数:corpidcorpsecret ,这两个参数登录企业微信开发者后台就可以获取到。接下来,直接写实现的方法:

// 获取企业微信的access_token
func GetWorkWechatAccessToken() string {corpId := "test" //替换成你自己的数据,下同secret := "test"url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%v&corpsecret=%v", corpId, secret)data, err := funcUtils.HttpGet(url)fmt.Println(data)fmt.Println(err)
}

然后在上面的 GetWorkWechatUserInfo() 方法中来调用这个方法:
在这里插入图片描述
可以看到,已经成功获取到企微返回的 access_token 了。但是这里需要仔细阅读企微的文档:注意:不能频繁调用gettoken接口,否则会受到频率拦截。
在这里插入图片描述
也就是说,这个接口返回的 access_token 在 7200秒之内是不变的,因此不能每次都去请求企微接口获取 access_token,需要放到缓存里。那么,最简单的,就是直接用 Redis给它存起来。

使用 Redis 将 access_token缓存起来

使用Redis也很简单,安装扩展 go get github.com/go-redis/redis/v8 ,然后如下配置:

// utils/redisUtil/goRedis.gopackage redisUtilimport ("context""github.com/go-redis/redis/v8""log"
)var ctx = context.Background()
var GoRdb *redis.Clientfunc init() {// 初始化 Redis 客户端GoRdb = redis.NewClient(&redis.Options{Addr:     "localhost:6379", // Redis 服务器地址Password: "",               // 密码(如果没有密码则为空)DB:       0,                // 使用的数据库编号})// 测试连接_, err := GoRdb.Ping(ctx).Result()if err != nil {log.Fatalf("Failed to connect to Redis: %v", err)}log.Println("Connected to Redis successfully")
}

GetWorkWechatUserInfo() 这个方法调用企微接口获取 access_token 之前先查一下有没有缓存,并且把整体代码结构也优化一下,该写配置文件的就写到配置文件。代码如下:

// conf/application.ymlworkWechat:requestUrl: https://qyapi.weixin.qq.com/cgi-bincorpId: xxxsecret: xxx
// controllers/userController/user.govar weworkConfig map[string]stringfunc init() {common.InitConfig()weworkConfig = make(map[string]string)weworkConfig["requestUrl"] = viper.GetString("workWechat.requestUrl")weworkConfig["corpId"] = viper.GetString("workWechat.corpId")weworkConfig["secret"] = viper.GetString("workWechat.secret")
}// 获取企业微信的access_token
func GetWorkWechatAccessToken() string {url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%v&corpsecret=%v", weworkConfig["corpId"], weworkConfig["secret"])data, err := funcUtils.HttpGet(url)if err != nil {fmt.Println("GetWorkWechatAccessToken调用三方接口出现了错误:", err)return ""}if data["access_token"].(string) == "" {fmt.Println("GetWorkWechatAccessToken获取到的access_token为空")return ""}return data["access_token"].(string)
}// 获取企业微信用户详情
func GetWorkWechatUserInfo(c *gin.Context) {var ctx = context.Background()workWechatAccessTokenKey := "workWechatAccessTokenKey"workWechatAccessTokenVal := redisUtil.GoRdb.Get(ctx, workWechatAccessTokenKey).Val()if workWechatAccessTokenVal == "" {workWechatAccessTokenVal = GetWorkWechatAccessToken()if workWechatAccessTokenVal == "" {controllers.ReturnError(c, 400, fmt.Sprintf("获取企业微信access_token失败"))}expiration, _ := time.ParseDuration("7000s") //7200-200redisUtil.GoRdb.Set(ctx, workWechatAccessTokenKey, workWechatAccessTokenVal, expiration)}var weworkRequestParams = map[string]string{"mobile": "132xxxx",}url := "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=" + workWechatAccessTokenValdata, err := funcUtils.HttpPost(url, weworkRequestParams, "application/json")if err != nil {fmt.Println("GetWorkWechatUserInfo调用企微接口出现了错误:", err)controllers.ReturnError(c, 400, "获取失败(-1)")}if data["userid"].(string) == "" {fmt.Println("GetWorkWechatUserInfo获取到的userid为空")controllers.ReturnError(c, 400, "获取失败(-2)")}result := map[string]string{"work_wechat_user_id": data["userid"].(string),}controllers.ReturnSuccess(c, 200, "获取成功", result, 1)
}

再次运行一下:

在这里插入图片描述
在这里插入图片描述
至此,已经成功获取到了企业微信的用户id。

代码优化

实现了基本功能之后,回过头来,我们再来阅读一下整体的代码,发现还有很大的优化空间。

代码逻辑拆分service层和controller层

上面代码中的 GetWorkWechatUserInfo()方法 把Gin框架的入口逻辑和实现的业务逻辑混在了一起,不方便代码的维护和复用。因此,可以拆分出来一层 service 层,或者说是逻辑层:

// service/work_wechat/workWechatUser.gopackage work_wechatvar weworkConfig map[string]stringtype WorkWechatUser struct {}func NewWorkWechatUser() *WorkWechatUser {return &WorkWechatUser{}
}func (we *WorkWechatUser) init() {common.InitConfig()weworkConfig = make(map[string]string)weworkConfig["requestUrl"] = viper.GetString("workWechat.requestUrl")weworkConfig["corpId"] = viper.GetString("workWechat.corpId")weworkConfig["secret"] = viper.GetString("workWechat.secret")
}// 获取企业微信的access_token
func (ctx *WorkWechatUser) GetWorkWechatAccessToken() (string, error) {//... 忽略部分代码return data["access_token"].(string), nil
}// 获取企业微信用户详情
func (ctx *WorkWechatUser) GetWorkWechatUserInfo() (map[string]string, error) {//... 忽略部分代码//返回结果result := map[string]string{"work_wechat_user_id": data["userid"].(string),}return result, nil
}

可以看的出来,在 service 中,不涉及任何 Gin 框架的逻辑,这样也方便我们这部分的业务逻辑代码的复用。接下来定义Gin框架的controller层,用来调用上面的service层:

//  controllers/userController/user.gopackage userControllerfunc GetWorkWechatUserInfo(c *gin.Context) {service := work_wechat.NewWorkWechatUser()data, err := service.GetWorkWechatUserInfo()if err != nil {controllers.ReturnError(c, 400, fmt.Sprintf("获取失败:%v", err))} else {controllers.ReturnSuccess(c, 200, "获取成功", data, 1)}
}

这样一来,代码看起来就简洁清晰了很多。

参数改为由客户端传递

上面在实现功能的时候,直接把请求参数的手机号写死在了代码里,这显然不太合理,因此需要把手机号作为参数从客户端传递。代码优化如下:

//  controllers/userController/user.go
func GetWorkWechatUserInfo(c *gin.Context) {// 定义一个 map 来存储请求体中的数据var requestData map[string]interface{}// 绑定请求体中的 JSON 数据到 mapif err := c.ShouldBindJSON(&requestData); err != nil {log.Printf("Failed to bind JSON: %v", err)c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to bind JSON"})return}if requestData["mobile"] == "" {controllers.ReturnError(c, 400, fmt.Sprintf("缺少参数mobile"))return}//.... 后续逻辑...
}

在这里插入图片描述

企微配置文件初始化

在最开始的时候,我把企微相关的配置信息写在了一个 map 里面:

var weworkConfig map[string]stringfunc init() {common.InitConfig()weworkConfig = make(map[string]string)weworkConfig["requestUrl"] = viper.GetString("workWechat.requestUrl")weworkConfig["corpId"] = viper.GetString("workWechat.corpId")weworkConfig["secret"] = viper.GetString("workWechat.secret")
}

但实际上,如果把配置信息放在 service 初始化的结构体里面可能会更优雅一些,因此,继续优化 service 层的代码如下:

// service/work_wechat/workWechatUser.gotype WorkWechatConfig struct {requestUrl stringcorpId     stringsecret     string
}func NewWorkWechatConfig() *WorkWechatConfig {return &WorkWechatConfig{requestUrl: viper.GetString("workWechat.requestUrl"),corpId:     viper.GetString("workWechat.corpId"),secret:     viper.GetString("workWechat.secret"),}
}func (ctx *WorkWechatConfig) GetWorkWechatAccessToken() (string, error) {url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%v&corpsecret=%v", ctx.corpId, ctx.secret)data, err := funcUtils.HttpGet(url)//.... 后续逻辑
}

这样,对于 controller 层:

service := work_wechat.NewWorkWechatConfig() //初始化配置信息
data, err := service.GetWorkWechatUserInfo(requestData["mobile"].(string))

这样的写法, 直接就会在调用的时候初始化企微相关的配置信息。

另外,记得把Redis的配置信息也放到配置文件里面:

// conf/application.ymlredis:host: localhostport: 6379password: ""db: 1
// utils/redisUtil/goRedis.govar ctx = context.Background()
var GoRdb *redis.Clientfunc InitRedis() {// 初始化 Redis 客户端GoRdb = redis.NewClient(&redis.Options{Addr:     fmt.Sprintf("%s:%s", viper.GetString("redis.host"), viper.GetString("redis.port")), //Redis服务器地址,格式:"localhost:6379"Password: viper.GetString("redis.password"),                                                  // 密码(如果没有密码则为空)DB:       viper.GetInt("redis.db"),                                                           // 使用的数据库编号})
}

个人感悟:很多逻辑看似简单,但不能只看不练,只有多加练习,才能学以致用,融会贯通。纸上得来终觉浅,绝知此事要躬行。刚开始做一件事情,比如学习一门新的编程语言或者做一个小功能,先不要想着怎么把它做的最好,而是要先做出来v0.1版本,先别管好不好,先能运行起来,后面再慢慢优化。很多人并不是有多少过人之处,只不过比其他人更加刻苦的去练习而已,练习的次数多了,自然就熟练了。
正所谓:“无他,唯手熟尔。”

完整源代码链接:https://gitee.com/rxbook/go-demo-2025

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com