go语言微信公众号开发后台接口封装

简介: go语言微信公众号开发后台接口封装

个人整理的小功能,把微信公众号开发涉及的一些常用接口做了个封装。


业余时间做了个有意思的小功能,每天早上7点准时给发天气预报,每晚8点发布一条英语说说,提醒自己不能忘记学习。


封装实现的功能有:


开发者首次接入、


创建菜单、


删除菜单、


发送模板消息、


接收公众号前端推送、


获取Token,获取关注者信息,


获取用户个人信息,


根据code获取个人信息(微信前端第三方应用页面接入授权会涉及。)


这里再介绍下微信前端第三方应用如何获取微信个人openid和个人信息的功能实现思路。


如何在微信前端开发的应用界面,获取用户openid和个人信息呢?方法还是有的,思路靠谱。


就是文档里描述的那几步授权操作,先获取code,再跳转,后台获取在传给前端。


附代码封装:


// WxReceiveCommonMsg 接收普通消息
type WxReceiveCommonMsg struct {
  ToUserName   string //接收者 开发者 微信号
  FromUserName string //发送者 发送方帐号(一个OpenID)
  Content      string //文本内容
  CreateTime   int64  //创建时间
  MsgType      string //消息类型
  MsgId        int64  //消息id
  PicUrl       string //图片url
  MediaId      string //媒体id
  Event        string //事件类型,VIEW
  EventKey     string //事件KEY值,设置的跳转URL
  MenuId       string
  Format       string
  Recognition  string
  ThumbMediaId string //缩略图媒体ID
}
// WxReceiveFunc (接收到消息之后,会将消息交于这个函数处理)
var WxReceiveFunc func(msg WxReceiveCommonMsg) error
// WxMakeSign 计算签名
func WxMakeSign(token, timestamp, nonce string) string {
  strs := []string{token, timestamp, nonce}
  sort.Strings(strs)
  sha := sha1.New()
  io.WriteString(sha, strings.Join(strs, ""))
  return fmt.Sprintf("%x", sha.Sum(nil))
}
// WxGetAccessToken 获取微信accesstoken
func WxGetAccessToken() string {
  url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%v&secret=%v", APPID, APPSECRET)
  resp, err := http.Get(url)
  if err != nil {
    fmt.Println("获取微信token失败", err)
    return ""
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("微信token读取失败", err)
    return ""
  }
  token := token{}
  err = json.Unmarshal(body, &token)
  if err != nil {
    fmt.Println("微信token解析json失败", err)
    return ""
  }
  return token.AccessToken
}
// WxGetUserList 获取关注者列表
func WxGetUserList(accessToken string) []gjson.Result {
  url := "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken + "&next_openid="
  resp, err := http.Get(url)
  if err != nil {
    fmt.Println("获取关注列表失败", err)
    return nil
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("读取内容失败", err)
    return nil
  }
  flist := gjson.Get(string(body), "data.openid").Array()
  return flist
}
// WxPostTemplate 发送模板消息
func WxPostTemplate(accessToken string, reqdata string, fxurl string, templateid string, openid string) {
  url := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken
  reqbody := "{\"touser\":\"" + openid + "\", \"template_id\":\"" + templateid + "\", \"url\":\"" + fxurl + "\", \"data\": " + reqdata + "}"
  fmt.Printf("WxPostTemplate:%#v\n", reqbody)
  resp, err := http.Post(url,
    "application/x-www-form-urlencoded",
    strings.NewReader(string(reqbody)))
  if err != nil {
    fmt.Println(err)
    return
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
// ReceiveCommonMsg
func ReceiveCommonMsg(msgData []byte) (WxReceiveCommonMsg, error) {
  fmt.Printf("received weixin msgData:\n%s\n", msgData)
  msg := WxReceiveCommonMsg{}
  err := xml.Unmarshal(msgData, &msg)
  if WxReceiveFunc == nil {
    return msg, err
  }
  err = WxReceiveFunc(msg)
  return msg, err
}
// WxCreateMenu 创建菜单
func WxCreateMenu(accessToken, menustr string) (string, error) {
  url := "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken
  fmt.Printf("WxCreateMenu:%s\n", menustr)
  resp, err := http.Post(url,
    "application/x-www-form-urlencoded",
    strings.NewReader(menustr))
  if err != nil {
    fmt.Println(err)
    return "", err
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println(err)
    return "", err
  }
  fmt.Println(string(body))
  return string(body), nil
}
// WxDelMenu 删除菜单
func WxDelMenu(accessToken string) (string, error) {
  url := "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=" + accessToken
  resp, err := http.Get(url)
  if err != nil {
    fmt.Println("删除菜单失败", err)
    return "", err
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("读取内容失败", err)
    return "", err
  }
  fmt.Println(string(body))
  return string(body), nil
}
// WxGetUserInfo 根据用户openid获取基本信息
func WxGetUserInfo(accessToken, openid string) (string, error) {
  url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", accessToken, openid)
  fmt.Println(url)
  resp, err := http.Get(url)
  if err != nil {
    fmt.Println("获取信息失败", err)
    return "", err
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("读取内容失败", err)
    return "", err
  }
  fmt.Println(string(body))
  return string(body), nil
}
// WxGetOpenidByCode 微信前端页面授权之后,会给前端页面路由里带一个code
func WxGetOpenidByCode(code string) (string, error) {
  url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", APPID, APPSECRET, code)
  resp, err := http.Get(url)
  if err != nil {
    fmt.Println("获取openid失败", err)
    return "", err
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("读取内容失败", err)
    return "", err
  }
  fmt.Println(string(body))
  return string(body), nil
}
// web API接口
// HandleWxLogin首次接入,成为开发者
func HandleWxLogin(c *gin.Context) {
  fmt.Printf("==>HandleWxLogin\n")
  echostr := c.DefaultQuery("echostr", "")
  if echostr != "" {
    fmt.Printf("==>echostr:%s\n", echostr)
    c.String(200, "%s", echostr)
    return
  }
}
// HandleWxPostRecv 处理微信公众号前端发起的消息事件
func HandleWxPostRecv(c *gin.Context) {
  fmt.Printf("==>HandleWxPostRecv Enter\n")
  data, err := c.GetRawData()
  if err != nil {
    log.Fatalln(err)
  }
  ReceiveCommonMsg(data)
}
// HandleWxGetOpenid
func HandleWxGetOpenid(c *gin.Context) {
  fmt.Printf("==>HandleWxGetOpenid Enter\n")
  code := c.Query("code")
  result, err := WxGetOpenidByCode(code)
  if err != nil {
    c.JSON(http.StatusOK, gin.H{
      "code": -1,
      "msg":  "获取openid失败" + err.Error(),
    })
    return
  }
  //WxDelMenu(accessToken)
  c.JSON(http.StatusOK, gin.H{
    "code": 0,
    "msg":  "成功",
    "data": result,
  })
}
// HandleWxGetUserInfo 根据前端请求来的openid获取用户信息
func HandleWxGetUserInfo(c *gin.Context) {
  fmt.Printf("==>HandleWxGetUserInfo Enter\n")
  opid := c.Query("openid")
  fmt.Printf("openid:%s\n", opid)
  token := WxGetAccessToken()
  result, err := WxGetUserInfo(token, opid)
  if err != nil {
    c.JSON(http.StatusOK, gin.H{
      "code": -1,
      "msg":  "获取用户信息失败" + err.Error(),
    })
    return
  }
  //WxDelMenu(accessToken)
  c.JSON(http.StatusOK, gin.H{
    "code": 0,
    "msg":  "成功",
    "data": result,
  })
}
func init() {
}


每日一句,每天发布一条英语句子,接口如下:


/**
每日一句api接口
*/
package apis
import (
  "encoding/json"
  "fmt"
  "github.com/tidwall/gjson"
  "io/ioutil"
  "net/http"
  "weixin/wxapi"
)
// SentTemplateID 每日一句的模板ID
var SentTemplateID = "Xhh6e2zuKbTXlplpMezHLkHuNIF0X1_ScJT3K3hi4wg"
// sentence 句子结构
type sentence struct {
  Content     string `json:"content"`
  Note        string `json:"note"`
  Translation string `json:"translation"`
}
// GetSay 获取每日一句
func GetSay() (sentence, string) {
  resp, err := http.Get("http://open.iciba.com/dsapi/?date")
  sent := sentence{}
  if err != nil {
    fmt.Println("获取每日一句失败", err)
    return sent, ""
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println("读取内容失败", err)
    return sent, ""
  }
  err = json.Unmarshal(body, &sent)
  if err != nil {
    fmt.Println("每日一句解析json失败")
    return sent, ""
  }
  fenxiangurl := gjson.Get(string(body), "fenxiang_img").String()
  fmt.Println(sent)
  return sent, fenxiangurl
}
//SendEverydaySay 发送每日一句
func SendEverydaySay() {
  req, fxurl := GetSay()
  if req.Content == "" {
    return
  }
  accessToken := wxapi.WxGetAccessToken()
  if accessToken == "" {
    return
  }
  flist := wxapi.WxGetUserList(accessToken)
  if flist == nil {
    return
  }
  reqdata := "{\"content\":{\"value\":\"" + req.Content + "\", \"color\":\"#0000CD\"}, \"note\":{\"value\":\"" + req.Note + "\"}, \"translation\":{\"value\":\"" + req.Translation + "\"}}"
  for _, v := range flist {
    wxapi.WxPostTemplate(accessToken, reqdata, fxurl, SentTemplateID, v.Str)
  }
}


相关文章
|
3月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
291 4
|
5月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
401 0
|
8月前
|
存储 Go
Go语言之接口与多态 -《Go语言实战指南》
Go 语言中的接口是实现多态的核心机制,通过一组方法签名定义行为。任何类型只要实现接口的所有方法即视为实现该接口,无需显式声明。本文从接口定义、使用、底层机制、组合、动态行为到工厂模式全面解析其特性与应用,帮助理解 Go 的面向接口编程思想及注意事项(如 `nil` 陷阱)。
231 22
|
3月前
|
JavaScript 前端开发 Java
【GoWails】Go做桌面应用开发?本篇文章带你上手Wails框架!一步步带你玩明白前后端双端的数据绑定!
wails是一个可以让你使用Go和Web技术编写桌面应用的项目 可以将它看作Go的快并且轻量级的Electron替代品。可以使用Go的功能,并结合现代化UI完成桌面应用程序的开发
676 4
|
3月前
|
Java 编译器 Go
【Golang】(5)Go基础的进阶知识!带你认识迭代器与类型以及声明并使用接口与泛型!
好烦好烦好烦!你是否还在为弄不懂Go中的泛型和接口而烦恼?是否还在苦恼思考迭代器的运行方式和意义?本篇文章将带你了解Go的接口与泛型,还有迭代器的使用,附送类型断言的解释
211 3
|
4月前
|
监控 前端开发 数据可视化
Github 12.3kstar, 3分钟起步做中后台?Go+Vue 脚手架,把权限、代码生成、RBAC 都封装好了
Go-admin 是基于 Gin + Vue 的中后台脚手架,集成 Casbin RBAC 权限、JWT 鉴权、GORM 数据库操作与 Swagger 文档,内置用户、角色、菜单等管理模块。提供代码生成器与表单构建器,支持多租户与多前端框架(Element UI/Arco/Ant Design),3 分钟快速搭建企业级后台,助力高效交付。
314 4
|
4月前
|
算法 iOS开发 CDN
“企业微信iPad协议”第 0x04 天:当朋友圈接口在凌晨 2:14 突然返回 404
新品上线紧急任务:300位经销商朋友圈同步海报。突破官方限制,利用企业微信iPad协议私有接口,自动化上传发布。凌晨遭遇404,迅速定位并修复算法版本问题,最终高效完成推送,点赞超4200。技术在文档之外,也在边界之内。
239 0
|
4月前
|
iOS开发
“企业微信iPad协议”第0x0B次编译:当朋友圈接口在凌晨悄然返回空数组
新品海报发布失败,排查发现企业微信iPad端因本地时间偏差超60秒,导致`ext_ticket`校验失败。NTP校准后恢复正常。问题根源:独立加签逻辑对时间敏感,且错误不提示。精准时间成合规关键。
271 0
|
7月前
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
395 61
|
11月前
|
自然语言处理 搜索推荐 小程序
微信公众号接口:解锁公众号开发的无限可能
微信公众号接口是微信官方提供的API,支持开发者通过编程与公众号交互,实现自动回复、消息管理、用户管理和数据分析等功能。本文深入探讨接口的定义、类型、优势及应用场景,如智能客服、内容分发、电商闭环等,并介绍开发流程和工具,帮助运营者提升用户体验和效率。未来,随着微信生态的发展,公众号接口将带来更多机遇,如小程序融合、AI应用等。