GO制作微信機器人的流程分析
這些天在學習Go,也寫了幾篇關于閱讀Gin后端項目代碼的博客。但編程這種,一定要實際上手練習,要不然都是紙上談兵。于是就想上手自己實際寫一些代碼來練練手。思來想去,不知道能寫些什么來練手。后來突然想到,之前寫過用Python做微信聊天機器人(博客傳送門),當時代碼沒有放到git上,后來重置了服務器導致代碼全部沒了。現(xiàn)在正好苦于不知道做什么項目練手,可以用Go也實現(xiàn)一套微信聊天機器人。
說干就干,照著之前自己寫的博客,看了下當時Python的代碼。轉(zhuǎn)而用Go優(yōu)化了下并實現(xiàn)。
0.回顧流程
根據(jù)之前Python寫的自動發(fā)消息的機器人可知,要想發(fā)消息就需要三個參數(shù):company_id、secret、angent_id。 對于這三個參數(shù)如何獲取,可參考文章開頭的傳送門。整個發(fā)送消息過程就是 首先通過company_id和secret來調(diào)用接口獲取token,再通過token和angent_id來給對應接口發(fā)送post請求,就可以把post請求體中的信息發(fā)送到微信上。
1.項目基礎配置
由于目前對Go的項目布局學習的還不是特別熟練,而且對于項目基礎部分如果從頭開始做的話,需要耗費大量時間。因此我使用了基于開源gin項目進行二次開發(fā)的方法,實現(xiàn)這個機器人。
前幾天在學習Gin時,發(fā)現(xiàn)了一位老哥封裝了個Gin腳手架,可以達到開箱即用目的。項目地址: github傳送門。 里邊把讀取配置文件,編寫路由,連接數(shù)據(jù)庫等多個操作均進行了實現(xiàn)。因此可以基于這個項目來進行二次開發(fā),做微信機器人。
在把項目clone下來后,可以先看下整個項目的布局,主要的業(yè)務核心代碼都放在了internal 下面。如果我們要實現(xiàn)一個主動給微信發(fā)消息的功能,那么多說了就是寫一個發(fā)送消息的方法,讓后端調(diào)用這個方法即可。
要想基于此項目來開發(fā)微信機器人,首先就要將三個參數(shù)配置上。項目中,對于各種參數(shù)均在config.yaml中配置,因為可以在這個配置文件中增加這三個參數(shù)的配置:
然后在代碼的config/autoload目錄下新增一個weCaht.go 文件,接收配置文件中的配置。
package autoload type WeChatConfig struct { AgentId string ini:"wechat" yaml:"agent_id" Secret string ini:"wechat" yaml:"secret" CompanyId string ini:"wechat" yaml:"company_id" } var WeChat = WeChatConfig{}
并且,將此配置加入到項目的配置集合中。在config/config.go中添加如下代碼:
這樣操作,就可以通過代碼來讀取配置文件了。在其他包中,可以通過如下方式來訪問對應的值
config.Config.WeChat.CompanyId //yaml中的company_id字段
2. Redis封裝
因為要給微信發(fā)送消息,首先要獲取到token,而官方介紹此token的有效時長為2小時。在之前Python的項目中,是直接將token寫到了文件中,通過文件來讀取。在此項目中,我想直接使用redis來存儲。因為使用redis來存儲的話,可以設置key值時長,過了這個時長就自動清除,這樣就方便了許多。
而我們基于這個gin-layout項目中,已經(jīng)對redis做了一層封裝,具體代碼可查看data/redis.go,主要是通過對外暴露一個Rdb的結構體,來操作redis
而目前我們這邊使用redis,只會用到對應的set和get方法。因此我對這個項目中的redis又做了一層封裝。只對外暴露set,get,del方法。
首先將Rdb變量名改為小寫,這樣就代表不對外暴露,然后在此文件中添加如下代碼
func SetRedis(key string, value string, t int64) bool { expire := time.Duration(t) * time.Second if err := rdb.Set(ctx, key, value, expire).Err(); err != nil { return false } return true } func GetRedis(key string) string { result, err := rdb.Get(ctx, key).Result() if err != nil { return “” } return result } func DelRedis(key string) bool { _, err := rdb.Del(ctx, key).Result() if err != nil { return false } return true }
這樣,后續(xù)使用redis時候,只需要調(diào)用data.SetRedis(xxx) 即可。
然后就是修改配置文件,啟用redis,這里根據(jù)實際的redis配置來寫即可。
3.消息體封裝
在最終給微信服務器發(fā)送post請求時,對應的請求體格式如下:
{ “touser”: “@all”, “msgtype”: “text”, “agentid”: “xxxxx”, “text”: {“content”: “xxxx”} }
因此,接下來可以對這個結構體做一個封裝。在model包下,新建一個send_msg.go文件
package model type wcSendcontent struct { Content string json:"content" } type WcSendMsg struct { ToUser string json:"touser" MsgType string json:"msgtype" AgentId string json:"agentid" Text wcSendcontent json:"text" } func (t *WcSendMsg) SetMessage(message string) { t.Text.Content = message }
這里針對message信息,專門對外暴露了一個方法來進行設置。
4.核心代碼
在設置好redis,消息體封裝后,就可以編寫核心的代碼了。主要就是通過發(fā)送http請求,獲取token,再通過token發(fā)送post請求來發(fā)送消息。我們可以在service包下新建一個weChat.go的文件,里邊新建一個SendWeChat方法來進行消息發(fā)送操作。
package service import ( “bytes” “encoding/json” “errors” “fmt”
c "github.com/wannanbigpig/gin-layout/config" "github.com/wannanbigpig/gin-layout/data" "github.com/wannanbigpig/gin-layout/internal/model" log "github.com/wannanbigpig/gin-layout/internal/pkg/logger" "github.com/wannanbigpig/gin-layout/pkg/utils" "go.uber.org/zap"
) /** @description: 給企微發(fā)送消息 @param {string} message 消息內(nèi)容 @param {string} msgType 消息類型 @return {*} */ func SendWeChat(message string, msgType string) error { redis_key := “access_token” // 嘗試從redis中讀取token accessToken := data.GetRedis(redis_key) http := &utils.HttpRequest{} // 若redis中的token已過期,則重新請求api獲取token if accessToken == “” { log.Logger.Info(“access token is null, will recall”) getTokenUrl := fmt.Sprintf(“https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s”, c.Config.WeChat.CompanyId, c.Config.WeChat.Secret) log.Logger.Info(“token_url”, zap.String(“url”, getTokenUrl)) http.Request(“GET”, getTokenUrl, nil) ret := make(map[string]interface{}) if err := http.ParseJson(&ret); err != nil { return err } marshal, _ := json.Marshal(ret) log.Logger.Info(string(marshal)) accessToken = fmt.Sprintf("%v", ret[“access_token”]) // 寫入redis 有效期2小時 data.SetRedis(redis_key, accessToken, 7200) } msg := &model.WcSendMsg{ ToUser: “@all”, MsgType: msgType, AgentId: c.Config.WeChat.AgentId, } msg.SetMessage(message) sendMsgUrl := fmt.Sprintf(“https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%v”, accessToken) log.Logger.Info(“sendMsgUrl = " + string(sendMsgUrl)) header := map[string]string{“Content-Type”: “application/json”} bytesData, _ := json.Marshal(msg) http.Request(“POST”, sendMsgUrl, bytes.NewReader(bytesData), header) log.Logger.Info(“bytes data = " + string(bytesData)) ret := make(map[string]interface{}) err := http.ParseJson(&ret) if err != nil { return err } if ret[“errcode”].(float64) != 0 { errmsg := fmt.Sprintf(”%v”, ret[“errmsg”]) return errors.New(errmsg) } return nil }
從上面代碼中可以看出,首先是通過redis來獲取token,若沒有則請求api獲取token,并將其寫入到redis中,有效期為2小時。然后生成一個之前封裝的消息的結構體,將AgentId和message進行填充后,通過發(fā)送post請求,已達到發(fā)消息的目的。
5.本地測試
若想驗證這個方法,可以通過對外提供一個接口,訪問此接口后調(diào)用發(fā)送消息的方法。
可以在controller目錄下新建一個weChat.go,在里邊實現(xiàn)一個get請求的方法,獲取請求中的msg參數(shù),然后調(diào)用剛才實現(xiàn)的發(fā)送企微的方法。
package wechat import ( “github.com/gin-gonic/gin” “github.com/wannanbigpig/gin-layout/internal/pkg/error_code” log “github.com/wannanbigpig/gin-layout/internal/pkg/logger” r “github.com/wannanbigpig/gin-layout/internal/pkg/response” “github.com/wannanbigpig/gin-layout/internal/service” ) func SendMsg(c *gin.Context) { msg, ok := c.GetQuery(“msg”) if !ok { msg = “please input message” } log.Logger.Info("send wechat message: " + msg) err := service.SendWeChat(msg, “text”) if err != nil { r.Resp().FailCode(c, error_code.FAILURE, err.Error()) return } r.Success(c, “success”) }
寫好后,將此方法綁定到路由上。在routers包下新建一個weChatRouter.go文件
package routers import ( “github.com/gin-gonic/gin” w “github.com/wannanbigpig/gin-layout/internal/controller/wechat” ) func setWeChatRouter(r *gin.Engine) { // version 1 v1 := r.Group(“wechat”) { v1.GET("/send", w.SendMsg) } }
這樣,后續(xù)可以通過wechat/send的url來請求這個接口。最后就是調(diào)用此綁定路由的方法,在routers/router.go中添加一行代碼即可
接下來啟動項目,比如發(fā)送一個msg=Hello,Golang 的請求
curl --location --request GET “http:// I P : {IP}: IP:{PORT}/wechat/send?msg=Hello,Golang”
執(zhí)行這個命令,就可以得到本文開頭的截圖。
當然,這個api接口主要是為了讓我們驗證,實際項目運行時,建議不要這么搞。因為這接口沒有任何鑒權的措施,如果對外暴露了出去,那么別人也可以肆意的調(diào)用這個接口給你的企微發(fā)送消息。
到此這篇關于利用go制作微信機器人的文章就介紹到這了,更多相關go微信機器人內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang實現(xiàn)Directional Channel(定向通道)
這篇文章主要介紹了Golang實現(xiàn)Directional Channel(定向通道),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-02-02Golang教程之不可重入函數(shù)的實現(xiàn)方法
這篇文章主要給大家介紹了關于Golang教程之不可重入函數(shù)的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-09-09Go源碼字符串規(guī)范檢查lint工具strchecker使用詳解
這篇文章主要為大家介紹了Go源碼字符串規(guī)范檢查lint工具strchecker使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06Go語言實現(xiàn)簡單的一個靜態(tài)WEB服務器
這篇文章主要介紹了Go語言實現(xiàn)簡單的一個靜態(tài)WEB服務器,本文給出了實現(xiàn)代碼和運行效果,學習Golang的練手作品,需要的朋友可以參考下2014-10-10