golang:后端实现微信订阅消息发送功能

前言

在日常开发中,难免会遇到需要微信订阅消息发送的需求,大部分的消息订阅发送使用的模板都是一次性发送的模板(因为长期订阅的消息模板申请时,需要服务性质是政务民生、医疗、交通、金融、教育等线下公共服务),而一次性的消息模板需要每次发送订阅消息后,用户再次订阅。我的办法是用户每次进入特定的页面后,让用户再次订阅。如下
在这里插入图片描述
用户有了订阅次数,会将订阅次数和对应的模板Id存储在微信后端,需要注意,当次数用完后,调用发送订阅消息接口会报错,如下图:在这里插入图片描述
下面,我们开始主要逻辑部分。

业务流程

在这里插入图片描述
订阅消息的发送主要分为两个部分,一是用户的订阅,二是真正给用户发送订阅消息。

一、用户的订阅

(1)openId的获取

用户首次订阅时,需要将用户的openId存储在数据库中,前端调用存储openId接口,入参是用户在系统的唯一标识,由前端提供,后端拿到code后,通过调用 “api.weixin.qq.com/sns/jscode2session” 接口获取openId,拿到openId后,需要将openId和userId形成关联关系并存储在数据库中,方便下次发送订阅消息时,拿到对应用户的openId。

需用到的接口是api.weixin.qq.com/sns/jscode2session,get请求,入参是code,appId,appSecret,code是前端获取到的用户的唯一标识,appId和appSecret是开发者在微信开发者平台拿到的小程序标识,最终发送的路径大致为“https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code”。

(2)openId的存储

拿到openId后,我们需要去系统里查看,当前登录人是否已经存储过对应的openId,如果已经存储过,可以不在做处理,否则需要将当前登陆人的userId和openId绑定在一起,存储到数据库当中,表结构可以设计的简单一些,总共就三个字段,id,userId,openId,实际情况根据业务而定。

二、发送订阅消息

(1)获取accessToken

在发送订阅消息前,需要先获取accessToken,微信对于accessToken有严格的要求,一个小程序生成一次accessToken的有效时间是2小时,而且微信对于“api.weixin.qq.com/cgi-bin/token”接口的调用次数有限制,不能频繁的调用,所以我采用的方法是将accessToken存入redis当中,设置过期时间为2小时,当accessToken过期,我们从redis里面获取accessToken时也正好获取不到,这个时候,再次调用“api.weixin.qq.com/cgi-bin/token”接口获取accessToken。

(2)组装入参

订阅消息的消息模板一般都有一些提示信息,这些提示信息需要在发送时组装好,我的消息模板大概是:
在这里插入图片描述

组装的结构如下:

	type SubscribeMessageData struct {
		Value string `json:"value"`
	}
	data := make(map[string]SubscribeMessageData)
	data["thing1"] = SubscribeMessageData{Value: "维修厂-平"}
	data["time2"] = SubscribeMessageData{Value: "2024年01月11日"}
	data["thing3"] = SubscribeMessageData{Value: "车辆 皖A666661,报修人待确认"}
	data["thing4"] = SubscribeMessageData{Value: "车辆总成"}

效果如下图:
在这里插入图片描述

(3)发送通知

目前,已经拿到,openId,accessToken,templateId,以及需要组装的参数。
根据微信开发文档的描述,我们已经足够调用“api.weixin.qq.com/cgi-bin/message/subscribe/send”接口了,需要注意的是有几个必传的参数:

  1. access_token
  2. touser:接收者(用户)的 openid
  3. template_id: 所需下发的订阅模板id
  4. page:小程序跳转链接,仅限本小程序内的页面。
  5. miniprogram_state:订阅消息跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版
  6. lang:进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN 返回参数
  7. data:模板内容,格式形如 { “key1”: { “value”: any }, “key2”: { “value”: any } }的object

尤其是page字段需要注意,该字段不传,则模板无跳转,我就在上面吃过亏!!!虽然默认跳转到首页,但还是需要传这个字段,那怕只传一个空字符,否则现象如下:
在这里插入图片描述

传参时需要注意,不同的类型传入的参数是有限制的,
本次模版用到的是date,name,thing和phrase,使用方式如下:

  1. date.DATA:年月日格式(支持+24小时制时间),支持填时间段,两个时间点之间用“~”符号连接,例如:2019年10月1日,或:2019年10月1日 15:01
  2. name.DATA:10个以内纯汉字或20个以内纯字母或符号,中文名10个汉字内;纯英文名20个字母内;中文和字母混合按中文名算,10个字内
  3. thing.DATA:20个以内字符,可汉字、数字、字母或符号组合
  4. phrase.DATA:5个以内汉字,5个以内纯汉字,例如:配送中

对应的json如下:

{
  "touser": "OPENID",
  "template_id": "TEMPLATE_ID",
  "page": "index",
  "data": {
      "name01": {
          "value": "某某"
      },
      "phrase01": {
          "value": "配送中"
      },
      "thing01": {
          "value": "广州至北京"
      } ,
      "date01": {
          "value": "2018-01-01"
      }
  }
}

返回的errcode也有多种情况,例如前言所说的,43101的错误情况,代表用户没有订阅次数,具体可以参考文档:

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html

代码处理

一、获取openId

	code := "??" // 用户在系统的唯一标识
	appId := "??" // 小程序appId
	appSecret := "??" // 小程序密钥

	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appId, appSecret, code)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("失败")
	}

	body, err := io.ReadAll(resp.Body)
	// 解析JSON响应
	var response map[string]interface{}
	json.Unmarshal([]byte(body), &response)

	// 获取openId
	openId := response["openid"].(string)
	fmt.Println(openId)

二、绑定userId,并存储到数据库

	appId := util.WeChatAppId// 小程序appId
	appSecret := util.WeChatAppSecret // 小程序密钥

	url := "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + req.Code + "&grant_type=authorization_code"
	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	body, err := io.ReadAll(resp.Body)
	// 解析JSON响应
	var response map[string]interface{}
	json.Unmarshal([]byte(body), &response)

	if response["errcode"] != nil && response["errcode"].(float64) != 0 {
		return errors.New(response["errmsg"].(string))
	}

	// 获取openId
	openId := response["openid"].(string)
	var open adminModels.SysUserWechat
	err = e.Orm.Table("sys_user_wechat").
		Where("open_id =?", openId).
		Where("user_id =?", req.Uid).
		First(&open).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return err
	}

	// 如果已经存储过,则不再存储
	if open.Id > 0 {
		return nil
	}
	open.OpenId = openId
	open.UserId = req.Uid
	err = e.Orm.Create(&open).Error
	return err

数据库中,SysUserWechat对应的表结构是:

// SysUserWechat 用户微信关联表
type SysUserWechat struct {
	models.Model
	UserId int    `json:"userId" gorm:"column:user_id"`
	OpenId string `json:"openId" gorm:"column:open_id"`
}

三、获取accessToken

	// 查看redis中是否有access_token
	redisClient := GetRedisClient()
	ctx := context.Background()
	accessToken, _ := redisClient.Get(ctx, "ACCESS_TOKEN_HCM_REPAIR").Result() // 从redis中获取accessToekn
	if accessToken == "" {
		appId := WeChatAppId
		appSecret := WeChatAppSecret
		apiURL := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret

		resp, err := http.Get(apiURL)
		if err != nil {
			return "", err
		}

		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}

		var response map[string]interface{}
		json.Unmarshal([]byte(body), &response)
		accessToken = response["access_token"].(string)
		redisClient.Set(ctx, "ACCESS_TOKEN_HCM_REPAIR", accessToken, time.Second*60*60*2) // 过期时间为2小时

四、发送订阅消息

url := "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken

message := adminModels.SubscribeMessage{
   ToUser:           openId, // 接收者(用户)的 openid
   TemplateID:       templateId, // 所需下发的订阅模板id
   MiniprogramState: MiniprogramState, // 订阅消息跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版
   Page:             Page, // 小程序跳转链接,仅限本小程序内的页面。
   Lang:             "zh_CN",// 进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN	返回参数
   Data:             data,// 需要插入的变量值
}

jsonStr, err := json.Marshal(message)
if err != nil {
   return err
}

req, err := http.NewRequest("POST", url, strings.NewReader(string(jsonStr)))
if err != nil {
   return err
}
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
   return err
}
// 解析JSON响应
var response map[string]interface{}
all, _ := io.ReadAll(resp.Body)
json.Unmarshal(all, &response)

if int(response["errcode"].(float64)) != 0 {
   log.Printf("errcode: %v, errmsg: %v", response["errcode"], response["errmsg"])
}
return nil

总结

在发送订阅消息时,不同的业务场景需要的代码肯定有所差别,但是万变不离其宗,需要的主要步骤就是上面这些,只要跟着上面的步骤,一步一步来,最后肯定会实现效果。最后祝看到这篇文章的家人们升官发财,万事如意!!

3√3
关注 关注
  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
wechat-go:带有golang微信消息处理程序(不适用于生产)
05-09
微信 简单高效的微信公众平台消息处理库 安装 $ go get github.com/feit/wechat 用法 package main import ( "net/http" "wechat" ) func wechatHandler ( this * wechat. Message ) { switch this . Msg [ "Content" ] { case "text" : this . Reply ( "hello text" ) case "news" : news := []wechat. News {} news = append ( news , wechat. News { Title : "Hello Golang" , Desc : "Golang is Go
发送订阅消息 微信小程序
qq_34586789的博客
08-12 1307
发送订阅消息 微信小程序 小程序单次授权后,用于发送订阅消息
微信小程序—订阅消息学习记录
cypersonal的博客
05-12 3348
首先说一下思路 1、在微信小程序后台配置模板 2、在小程序上让用户触订阅消息提示 将配好的模板id,使用wx.requestSubscribeMessage,使用户同意订阅消息,获取一次可以订阅的机会 3、后台发送消息subscribeMessage.send 2.1 获取用户授权结果,在success函数中获取通过res的判断,用户是否选择永久允许,允许了哪个模板 2.2 wx.getString()也可以获取用户订阅消息,但是只有用户选择总是默认允许的模板才能查的到。一次的授权是查不到的。 3.1
微信小程序登录和消息推送(基于当前最新,不用看其他的了)
也无风雨也无情
04-17 563
accesstoken有有效期,所有需要在后端缓存,获取手机号和openId的code由前端提供,两个code不相同,且只能使用一次。推送的前提是前端需要掉起一次授权页面,该用户授权后,才可以往这个人的openId推送消息。2.推送的data属性为小程序自己生成,所以在建好模板后最好在本地存一份,这样可以动态使用,不用写死。另外,现在的需求一般是微信一键登录,所以在本地系统没有对应用户时可以注册后帮助用户进行登录。3.微信工具类,用户获取accesstoken,手机号,openId。
微信小程序模板消息推送
热门推荐
weixin_45767235的博客
12-24 1万+
微信小程序模板消息推送
Golang:通过小程序获取微信 openid
03-29
为什么要获取小程序的 openid 在开微信小程序的过程中,小程序...我们需要在小程序中调用 wx.login() 获取 code 码,然后将这个 code 码发送后端后端带着这个 code 码和 appid,appsecret 向微信接口起 http
openwechat:Golang微信客户端
04-12
个人微信号使用前提1、你的微信号必须能够在成功登录2、golang版本大于等于1.11安装go getgo get github.com/eatMoreApple/openwechatgo modrequire github.com/eatMoreApple/openwechat快速开始登录微信package...
golang整合微信支付
04-06
golang整合微信支付
golang实现微信小程序商城后台系统(moshopserver)
09-17
golang实现微信小程序商城后台系统(moshopserver)】 本文将深入探讨如何使用Golang语言构建微信小程序的后台系统,moshopserver。Golang作为一门相对较新的编程语言,以其简洁的语法和高效的性能受到了许多...
go-framework:golang后端框架和代码规范
05-16
维罗妮卡golang后端框架和代码规范Veronica是golang编写的后端服务框架。 您可以快速构建自己的后端服务和代码规范。 Veronica提供了许多有用的基础结构和代码规范,基本上涵盖了后端服务应具有的大多数元素。 并且...
微信小程序-小程序订阅消息(四)
MinggeQingchun的博客
05-20 9745
消息能力是小程序能力中的重要组成,我们为开者提供了订阅消息能力,以便实现服务的闭环和更优的体验。订阅消息推送位置:服务通知订阅消息条件:用户自主订阅订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面。
Golang -- openwechat微信发送消息、自动回复
zhangdm的博客
01-16 5601
微信发送消息、自动回复
使用Java实现微信小程序订阅消息
m0_47214210的博客
02-17 4160
使用spring boot实现微信小程序的订阅消息发送
微信小程序消息模板设计及实现
lmyhplay的博客
03-07 5509
第三方平台小程序消息模板设计
小程序发送订阅消息
最新发布
weixin_29081163的博客
07-01 76
官方文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html参数说明:touser : 接收者openidtemplate_...
eggjs实现微信发送订阅功能
weixin_50307964的博客
04-14 256
订阅功能又分为一次订阅和长期订阅功能,如果是一次订阅的话需要每次都授权,否则通知不到用户;获取access_token的目的主要是为了发送订阅消息的时候需要携带这个值才能成功发送订阅消息通知用户;这儿需要传递过来的code(前台获取的code)然后通过小程序的开放接口以及appid和appSecret获得openid;我做的这个可能比较粗糙,大家可以根据文档做一些优化功能!: row格式,data中的time24需要和微信公众号里面配置的订阅消息字段保持一致。要实现这种功能就需要用到小程序的订阅功能
java实现微信小程序订阅通知
kuanhu1102的博客
09-18 618
因为我当时需要推送的内容是小程序端页面表格填写的,但是名称字段没有做格式限制,导致这个字段在测试的时候输入了数字内容,发送通知的时候就会报错。第二个是切勿“滥用”access_token,这里的“滥用”是指获取access_token的入口不唯一。小程序的access_token有效期为7200秒,所以可以考虑将其放入缓存并定期刷新,而不是哪里需要哪里重新获取,这样很有可能导致第一次获取的access_token,因为不知道哪个地方又获取了一次,导致access_token失效。
小程序利用golang beego实现订阅消息服务端
hotqin888的专栏
02-20 1784
微信由模板消息改为订阅消息,其实我压根也不知道模板消息是个啥子,就在前几天,心血来潮,想试试这个消息订阅现目前只能是订阅消息,模板消息已经停止了。 开始搞不清楚这个逻辑,比如,服务端是否要保存用户订阅的记录啊?开始还写了,用户订阅消息,我将用户胡openid和消息模板id存到数据库。 后来想想不对,用户取消订阅没有触的事件呀,那我的数据库不就无法删除了嘛。 对的。咱们的服务端不需要存...
springboot优雅的实现微信小程序订阅功能
weixin_53107062的博客
07-30 806
翻译一下就是:不用每次订阅的时候都去获取一次access_token,access_token的有效期是2个小时,所以可以。根据官方文档的描述,服务端通过发送一个https请求将订阅模板发送至用户微信。使用线程池或引入消息队列(如rabbitmq)进行异步处理。access_token的获取应当参照优化后的代码进行处理。
写文章

热门文章

  • golang:后端实现微信订阅消息发送功能 2131
  • golang:后端实现阿里云人脸识别功能 1203

最新评论

  • golang:后端实现阿里云人脸识别功能

    CSDN-Ada助手: 非常棒的博客!看到你成功地利用了阿里云的人脸识别功能,真是令人鼓舞!希望你能继续分享更多关于后端开发的经验和技巧。在扩展知识方面,你可以学习更多关于数据安全和隐私保护的内容,以确保用户的人脸数据得到妥善处理。期待你的下一篇博客! 如何写出更高质量的博客,请看该博主的分享:https://blog.csdn.net/lmy_520/article/details/128686434?utm_source=csdn_ai_ada_blog_reply2

  • golang:后端实现微信订阅消息发送功能

    CSDN-Ada助手: Go 技能树或许可以帮到你:https://edu.csdn.net/skill/go?utm_source=AI_act_go

  • golang:后端实现微信订阅消息发送功能

    zhou1225283915: 大佬写的很详细,跟着写我也实现了不同的订阅消息

最新文章

  • golang:后端实现阿里云人脸识别功能
2024年2篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家四川大型商场美陈制造威海城市玻璃钢雕塑玻璃钢人物雕塑造价辽宁海洋生物玻璃钢雕塑制造成都玻璃钢雕塑制品厂家玻璃钢雕塑设计方案武穴玻璃钢花盆花器上海艺术商场美陈武汉镜面不锈钢玻璃钢彩绘雕塑肖像玻璃钢雕塑定制厂家江苏季节性商场美陈厂家供应深圳商场美陈生产企业玻璃钢园林雕塑厂商河北户外商场美陈生产厂家福建户外商场美陈价格高安玻璃钢狮子雕塑山东人物玻璃钢雕塑订做价格上海玻璃钢雕塑摆件厂家直销湛江玻璃钢雕塑凳子徐州玻璃钢浮雕人物山水雕塑常州玻璃钢商场美陈福州户外玻璃钢雕塑联系方式盐城玻璃钢人物雕塑特色玻璃钢花盆多少钱湛江创新型的玻璃钢雕塑校园玻璃钢人物雕塑手工制作柳林玻璃钢花盆花器合肥景观玻璃钢雕塑生产厂家石首玻璃钢仿铜雕塑天津户外玻璃钢雕塑市场香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化