【笔记】Go语言实现微信服务号消息推送

前言

Go语言实现微信服务号消息推送

准备工作

注册微信公众号

订阅号不具有高级接口能力,无法完成消息推送
服务号必须是企业用户注册,个人用户无法注册

  • 登录管理员后台->设置与开发->基本配置->勾选我同意->成为开发者

  • 启用开发者密码

  • 通过开发者的微信扫码验证身份

  • 通过公众号的账户密码验证身份

  • 获取AppIDAppSecret

注意,AppSecret只显示一次,如果重新获取将会重置,注意妥善保存

  • 完成

设置IP地址白名单

  • 配置IP白名单

  • 设置IP白名单,每行一个IP地址,可以配置多个

  • 设置完成关闭窗口

设置消息推送模板

  • 在服务号后台,开通消息推送功能->设置所属行业(241)->设置消息推送模板,得到消息推送模板编号template_id

获取接收消息的用户的OpenID

  • 如果是批量发给所有用户,需要获取所有用户的OpenID

  • 如果是单独发给指定用户,需要在用户关注公众号后,将用户的OpenID存储在数据库中用于识别身份,然后从数据库中获取OpenID,实现向指定用户推送消息

  • 发送请求获取AccessToken

AccessToken有效期为2小时

1
2
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=<appid>&secret=<secret>
Accept: application/json
  • 获取所有关注公众号的用户的OpenID

<access_token>:上一步骤获取的AccessToken

1
2
GET https://api.weixin.qq.com/cgi-bin/user/get?access_token=<access_token>
Accept: application/json

正文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main

import (
"encoding/json"
"fmt"
"github.com/google/uuid"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
)

// GetWechatPublicAccessTokenResponseEntity 获取微信公众平台AccessToken响应实体
type GetWechatPublicAccessTokenResponseEntity struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
}

// WechatPublicSendMessageResponseEntity 获取微信公众平台消息推送响应实体
type WechatPublicSendMessageResponseEntity struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
MsgID int `json:"msgid"`
}

func main() {
var appID = "<appid>"
var secret = "<secret>"
var openID = "<openid>"
var templateID = "<template_id>"

// 获取AccessToke
var accessToken string
if res, err := http.Get(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appID, secret)); err != nil {
log.Println(err.Error())
} else {
defer res.Body.Close()
if res, err := ioutil.ReadAll(res.Body); err != nil {
log.Println(err.Error())
} else {
var response GetWechatPublicAccessTokenResponseEntity
if err := json.Unmarshal(res, &response); err != nil {
log.Println(err.Error())
}
accessToken = response.AccessToken
}
}

// 生成UUID
var uuidString string
if res, err := uuid.NewUUID(); err != nil {
log.Println(err.Error())
} else {
uuidString = res.String()
}
// 获取当前时间
var currentTimeTime = time.Now()
var currentTimeString = fmt.Sprintf(
"%04d年%02d月%02d日",
currentTimeTime.Year(),
int(currentTimeTime.Month()),
currentTimeTime.Day(),
)
// 根据openid向指定用户发送登录成功的消息
var payloadMap map[string]interface{} = map[string]interface{}{
"touser": openID,
"template_id": templateID,
"client_msg_id": uuidString,
"data": map[string]interface{}{
"thing6": map[string]string{
"value": "登录用户名",
},
"thing4": map[string]string{
"value": "登录方式",
},
"time3": map[string]string{
"value": currentTimeString,
},
},
}
// payloadMap 转换为 JSON格式字符串
var payloadString string
if res, err := json.Marshal(payloadMap); err != nil {
log.Println(err.Error())
} else {
payloadString = string(res)
}
// 推送消息
if res, err := http.Post(
fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s", accessToken),
"application/json",
strings.NewReader(payloadString),
); err != nil {
log.Println(err.Error())
} else {
defer res.Body.Close()
if res, err := ioutil.ReadAll(res.Body); err != nil {
log.Println(err.Error())
} else {
log.Println(string(res))
var response WechatPublicSendMessageResponseEntity
if err := json.Unmarshal(res, &response); err != nil {
log.Println(err.Error())
}
if response.ErrCode == 0 {
log.Println("Success!")
}
}
}
}

完成

参考文献

微信官方文档——公众号
微信官方文档——公众号