微信开发中的消息推送

文章目录


​ 因为微信开发需要配置服务器域名,所以需要一个已备案的域名。可以通过 NPS内网穿透工具的增强功能,使用 https将域名的 https请求穿透到本地网关端口。 NPS使用: NPS内网穿透-CSDN博客

​ 文末附有后端服务代码。

1. 小程序消息推送

1.1 功能介绍

​ 消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验。

​ 订阅消息推送位置:服务通知

​ 订阅消息下发条件:开发者通过一定的方式触发用户主动订阅

​ 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面

​ 简单来讲,用户通过点击或支付完成后调用模板消息授权的弹窗,当用户成功授权后,开发者才可以通过调用微信接口,使用用户已授权模板发送订阅消息,进行消息提醒。

1.2 前提条件

​ 一个微信小程序账号,一个已备案域名。

1.3 准备工作

1.3.1 开通订阅消息

​ 登录小程序账号后,点击功能下的订阅消息,点击开通
在这里插入图片描述

1.3.2 配置服务器域名

​ 登录小程序账号后,点击开发的开发管理,在开发设置下,找到服务器域名模块,修改request合法域名为 自己已备案域名。
在这里插入图片描述

1.3.3 生成小程序密钥

​ 若没有生成小程序密钥,则需要在开发设置下,生成小程序密钥。

1.4 订阅消息

1.4.1 一次性订阅

​ 一次性订阅消息指的是:用户订阅模板消息一次,只能推送一条模板消息。当第一次推送过后,用户尚未进行下一次的订阅操作,再次推送就会提示 用户未订阅消息 的错误信息。

1)获取并保存用户openid

​ 获取用户openid主要为两步,小程序获取用户登录凭证返回至后端服务,后端服务通过登录凭证获取用户的openid

① 获取登录凭证

​ 小程序通过调用登录开放接口wx.login()获取到用户登陆凭证code,发送到自己的后端服务。

​ 详情请见: 微信官方文档-wx.login

参数:

Object object

属性类型默认值必填说明
timeoutnumber超时时间,单位ms
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)
object.success 回调函数

参数:

Object res

属性类型说明
codestring用户登录凭证(有效期五分钟)。
object.fail 回调函数

参数:

Object err

属性类型说明最低版本
errMsgString错误信息
errnoNumbererrno 错误码,错误码的详细说明参考 Errno错误码2.24.0
示例代码:
wx.login({
  success (res) {
    if (res.code) {
      //发起网络请求
      wx.request({
        url: 'https://example.com/wx/login',
        data: {
          code: res.code,
          userId:"001"
        }
      })
    } else {
      console.log('登录失败!' + res.errMsg)
    }
  }
})
② 获取用户openid

​ 后端服务通过调用 code2Session接口,获取到用户openid

​ 详情请见: 微信官方文档-小程序登录

接口文档:
GET https://api.weixin.qq.com/sns/jscode2session
请求参数:
属性类型必填说明
appidstring小程序 appId
secretstring小程序 appSecret
js_codestring登录时获取的 code
grant_typestring授权类型,此处只需填写 authorization_code
返回参数
属性类型说明
session_keystring会话密钥
unionidstring用户在开放平台的唯一标识符
errmsgstring错误信息
openidstring用户唯一标识
errcodeint32错误码
错误码:
错误码错误码取值解决方案
40029code 无效js_code无效
45011api minute-quota reach limit mustslower retry next minuteAPI 调用太频繁,请稍候再试
40226code blocked高风险等级用户,小程序登录拦截 。风险等级详见用户安全解方案
-1system error系统繁忙,此时请开发者稍候再试
示例代码:
    private final String appletAppid = "小程序的appid";
    private final String appletSecret = "小程序的appSecret";
    
    public void getAppletOpenid(String code) {
        RestTemplate restTemplate = new RestTemplate();
        // 调用 code2Session 接口
        String codeJson = restTemplate.getForObject("https://api.weixin.qq.com/sns/jscode2session" +
                "?appid=" + appletAppid +
                "&secret=" + appletSecret +
                "&js_code=" + code +
                "&grant_type=authorization_code", String.class);
        // 反序列化
        Map bean = JSONUtil.parseObj(codeJson).toBean(Map.class);
        
        if (bean.get("openid") != null){
            saveOpenid(bean.get("openid").toString());
        }else {
            throw new RuntimeException("openid获取失败, 错误码:" + bean.get("errcode") + " 错误信息:" + bean.get("errmsg"));
        }
    }
    
    private void saveOpenid(String openid){
        // 可以从token中获取到用户信息,并将openid保存至数据库
        System.out.println("用户的openid:" + openid + " 获取成功");
    }
2)用户授权

​ 这里我们首先需要选择需要用户授权的模板,然后让用户调起订阅界面。

① 选用模板

​ 为了简单测试,这里选用了公共模板库中的一个下单提醒模板。若为了满足业务需求,可以申请一个模板(每月有申请次数限制!)。

​ 如果公共模板库没有模板,需先在小程序设置中,选择服务类目。

在这里插入图片描述
在这里插入图片描述

​ 申请模板在公共模板库的最后一页帮忙我们完善模板库,点击进去,完善相关信息,等待审核。若审核通过,就可以使用了。

在这里插入图片描述
在这里插入图片描述

② 用户调用

​ 通过用户点击调起客户端小程序订阅消息模板界面,返回用户订阅消息模板的操作结果。当用户勾选了"总是保持以上选择,不再询问",在下次授权时,默认确定,不再进行弹窗提示(真机调试才会出现)。

​ 详情请见: 微信官方文档-wx.requestSubscribeMessage

接口:
wx.requestSubscribeMessage(Object object)
参数:

Object object

属性类型默认值必填说明
tmplIdsArray需要订阅的消息模板的id的集合,一次调用最多可订阅3条消息(注意:iOS客户端7.0.6版本、Android客户端7.0.7版本之后的一次性订阅/长期订阅才支持多个模板消息,iOS客户端7.0.5版本、Android客户端7.0.6版本之前的一次订阅只支持一个模板消息)消息模板id在[微信公众平台(mp.weixin.qq.com)-功能-订阅消息]中配置。每个tmplId对应的模板标题需要不相同,否则会被过滤。
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)
object.success 回调函数

参数

Object res

属性类型说明
errMsgString接口调用成功时errMsg值为’requestSubscribeMessage:ok
[TEMPLATE_ID: string]String[TEMPLATE_ID]是动态的键,即模板id,值包括’accept’、‘reject’、‘ban’、‘filter’。'accept’表示用户同意订阅该条id对应的模板消息,'reject’表示用户拒绝订阅该条id对应的模板消息,'ban’表示已被后台封禁,'filter’表示该模板因为模板标题同名被后台过滤。例如 { errMsg: “requestSubscribeMessage:ok”, zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: “accept”} 表示用户同意订阅zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE这条消息
object.fail 回调函数

参数

Object res

属性类型说明
errMsgString接口调用失败错误信息
errCodeNumber接口调用失败错误码
错误码:
errCodeerrMsg说明
10001TmplIds can't be empty参数传空了
10002Request list fail网络问题,请求消息列表失败
10003Request subscribe fail网络问题,订阅请求发送失败
10004Invalid template id参数类型错误
10005Cannot show subscribe message UI无法展示 UI,一般是小程序这个时候退后台了导致的
20001No template data return, verify the template id exist没有模板数据,一般是模板 ID 不存在 或者和模板类型不对应 导致的
20002Templates type must be same模板消息类型 既有一次性的又有永久的
20003Templates count out of max bounds模板消息数量超过上限
20004The main switch is switched off用户关闭了主开关,无法进行订阅
20005This mini program was banned from subscribing messages小程序被禁封
20013Reject DeviceMsg Template不允许通过该接口订阅设备消息
示例代码:
    var TemplateId = '第一步选用的模板Id'
    var TemplateStatus = wx.getStorageSync('TemplateID')
    if(TemplateStatus != 'accept'){
      wx.requestSubscribeMessage({
        tmplIds: [TemplateId],
        complete (res) {
          console.log("complete: ",res)
          wx.setStorageSync('TemplateId', res[TemplateId])
        },
      })
    }
效果展示:

PC效果:

在这里插入图片描述
真机效果:
在这里插入图片描述

3)发送订阅消息

​ 后端服务首先调用getAccessToken接口,获取接口调用凭证。再调用sendMessage接口,实现向用户推送一条已订阅的模板消息。

① 获取接口调用凭证

token有效期为7200s

​ 详情请见: 微信官方文档-获取接口调用凭据

接口:
GET https://api.weixin.qq.com/cgi-bin/token
请求参数:
属性类型必填说明
grant_typestring填写 client_credential
appidstring唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且帐号没有异常状态)
secretstring唯一凭证密钥,即 AppSecret,获取方式同 appid
返回参数:
属性类型说明
access_tokenstring获取到的凭证
expires_innumber凭证有效时间,单位:秒。目前是7200秒之内的值。
其他说明:
  • access_token 的存储至少要保留 512 个字符空间;
  • access_token 的有效期目前为 2 个小时,需定时刷新,重复获取将导致上次获取的 access_token 失效;
  • access_token 的有效期通过返回的 expires_in 来传达,目前是7200秒之内的值,中控服务器需要根据这个有效时间提前去刷新。在刷新过程中,中控服务器可对外继续输出的老 access_token,此时公众平台后台会保证在5分钟内,新老 access_token 都可用,这保证了第三方业务的平滑过渡;
示例代码:
    private String getAccessToken(){
    	// 这里可以结合redis进行缓存
        RestTemplate restTemplate = new RestTemplate();
        String accessTokenJson = restTemplate.getForObject("https://api.weixin.qq.com/cgi-bin/token" +
                "?grant_type=client_credential" +
                "&appid=" + appletAppid +
                "&secret=" + appletSecret, String.class);
        Map bean = JSONUtil.parseObj(accessTokenJson).toBean(Map.class);
        if (bean.get("access_token") != null){
            return bean.get("access_token").toString();
        }else {
            throw new RuntimeException("凭证获取失败, 错误码:" + bean.get("errcode") + " 错误信息:" + bean.get("errmsg"));
        }
    }
② 推送订阅消息

​ 详情请见: 微信官方文档-推送订阅消息

接口:
POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
Post参数:
属性类型必填说明
access_tokenstring接口调用凭证,该参数为 URL 参数,非 Body 参数。使用access_token或者authorizer_access_token
template_idstring所需下发的订阅模板id
pagestring点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
touserstring接收者(用户)的 openid
datastring模板内容,格式形如 { “key1”: { “value”: any }, “key2”: { “value”: any } }的object
miniprogram_statestring跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
langstring进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
返回参数:
属性类型说明
errcodenumber错误码
errmsgstring错误信息
错误码:
错误码错误码取值解决方案
40001invalid credential access_token isinvalid or not latest获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口
40003invalid openid不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID
40014invalid access_token不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口
40037invalid template_id不合法的 template_id
43101用户未订阅消息检查订阅弹窗回调结果或事件推送确认是否订阅成功,检查是否一次性订阅的次数之前已下发完
43107订阅消息能力封禁检查账号是否被封禁订阅消息能力,检查模板id对应的模板是否被封禁
43108并发下发消息给同一个粉丝检查是否有同时下发多个消息给同一粉丝的情况
45168命中敏感词检查下发消息中是否带有敏感词
47003参数错误根据wiki文档检查data结构格式是否正确,检查各个关键词是否满足对应规则
其他说明:
参数类别参数说明参数值限制说明
thing.DATA事物20个以内字符可汉字、数字、字母或符号组合
number.DATA数字32位以内数字只能数字,可带小数
letter.DATA字母32位以内字母只能字母
symbol.DATA符号5位以内符号只能符号
character_string.DATA字符串32位以内数字、字母或符号可数字、字母或符号组合
time.DATA时间24小时制时间格式(支持+年月日),支持填时间段,两个时间点之间用“~”符号连接例如:15:01,或:2019年10月1日 15:01
date.DATA日期年月日格式(支持+24小时制时间),支持填时间段,两个时间点之间用“~”符号连接例如:2019年10月1日,或:2019年10月1日 15:01
amount.DATA金额1个币种符号+10位以内纯数字,可带小数,结尾可带“元”可带小数
phone_number.DATA电话17位以内,数字、符号电话号码,例:+86-0766-66888866
car_number.DATA车牌8位以内,第一位与最后一位可为汉字,其余为字母或数字车牌号码:粤A8Z888挂
name.DATA姓名10个以内纯汉字或20个以内纯字母或符号中文名10个汉字内;纯英文名20个字母内;中文和字母混合按中文名算,10个字内
phrase.DATA汉字5个以内汉字5个以内纯汉字,例如:配送中
enum.DATA枚举值只能上传枚举值范围内的字段值调用接口获取参考枚举值

​ 符号表示除中文、英文、数字外的常见符号,不能带有换行等控制字符。 时间格式支持HH:MM:SS或者HH:MM。 日期包含年月日,为y年m月d日,y年m月、m月d日格式,或者用‘-’、‘/’、‘.’符号连接,如2018-01-01,2018/01/01,2018.01.01,2018-01,01-01。 每个模板参数都会以类型为前缀,例如第一个数字模板参数为number01.DATA,第二个为number02.DATA

示例代码:
    public void appletSendMessage() {
        String accessToken = getAccessToken();
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("touser", "用户的openid");
        map.put("template_id", "消息模板id");
        // 模板数据
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("thing1", Collections.singletonMap("value", "测试订阅推送"));
        data.put("number2", Collections.singletonMap("value", 10001));
        data.put("amount3", Collections.singletonMap("value", "100元"));
        data.put("thing4", Collections.singletonMap("value", "测试订单消息推送"));
        map.put("data", data);
        HttpEntity<Map<String, Object>> request = new HttpEntity<Map<String, Object>>(map);
        String resultJson = restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/message/subscribe/send" +
                "?access_token=" + accessToken, request, String.class);
        Map bean = JSONUtil.parseObj(resultJson).toBean(Map.class);
        if (Integer.parseInt(bean.get("errcode").toString()) != 0){
            throw new RuntimeException("发送失败, 错误码:" + bean.get("errcode") + " 错误信息:" + bean.get("errmsg"));
        }
    }
效果展示:

在这里插入图片描述

1.4.2 长期订阅

​ 目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下。 因为目前没有涉及线下服务业务,所以本文不进行过多介绍。

2. 公众号消息推送

2.1 一次性订阅消息

2.1.1 功能介绍

​ 开发者可以通过一次性订阅消息授权让微信用户授权第三方移动应用(接入说明)或公众号,获得发送一次订阅消息给到授权微信用户的机会。授权微信用户可以不需要关注公众号。微信用户每授权一次,开发者可获得一次下发消息的权限。(注意:同一用户在同一scene场景值下的多次授权不累积下发权限,只能下发一条。若要订阅多条,需要不同scene场景值)

​ 消息下发位置说明:对于已关注公众号的,消息将下发到公众号会话里;未关注公众号的,将下发到服务通知。

​ 详情请见:微信官方文档-公众号一次性订阅消息

2.1.2 前提条件

​ 一个已认证的服务号,一个已备案域名

2.1.3 准备工作

​ **注意:**若服务号未进行认证,则不能进行相关信息的配置。

配置业务域名

​ 登录服务号账号后,点击设置与开发下的公众号设置,选择功能设置,找到业务域名进行设置。

​ 这里我把TXT文件放到了后端服务的 resources下的static目录下,通过nps的使用https,即可将服务请求转发到本机后端服务完成校验。
在这里插入图片描述
在这里插入图片描述

2.1.4 消息推送

1)用户授权

​ 在确保微信公众账号拥有订阅消息授权的权限的前提下(已认证的公众号即有权限,可登录公众平台在接口权限列表处查看),引导用户在微信客户端打开如下链接:

https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=wxaba38c7f163da69b&scene=1000&template_id=1uDxHNXwYQfBmXOfPJcjAS3FynHArD8aWMEFNRGSbCc&redirect_url=http%3a%2f%2fsupport.qq.com&reserved=test#wechat_redirect

​ **注意:**该参数中的模板id在接口权限列表中查看,并非准备阶段中的模板id。若使用准备阶段模板id,则会提示模板id不对。
在这里插入图片描述

参数:
参数是否必须说明
action直接填get_confirm即可
appid公众号的唯一标识
scene重定向后会带上scene参数,开发者可以填0-10000的整型值,用来标识订阅场景值
template_id订阅消息模板ID,登录公众平台后台,在接口权限列表处可查看订阅模板ID
redirect_url授权后重定向的回调地址,请使用UrlEncode对链接进行处理。 注:要求redirect_url的域名要跟登记的业务域名一致,且业务域名不能带路径。 业务域名需登录公众号,在设置-公众号设置-功能设置里面对业务域名设置。
reserved用于保持请求和回调的状态,授权请后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验,开发者可以填写a-zA-Z0-9的参数值,最多128字节,要求做urlencode
#wechat_redirect无论直接打开还是做页面302重定向时,必须带此参数
示例代码:
  	// 这里通过生成二维码引导用户授权
  	public void officialAuth(HttpServletResponse response) {
        String url = "https://mp.weixin.qq.com/mp/subscribemsg" +
                "?action=get_confirm" +
                "&appid=" + officialAppid +
                "&scene=" + "0001" +
                "&template_id=" + "接口权限列表处一次性订阅消息模板id" +
                "&redirect_url=" + "https://业务域名/wx/official/send( urlEncode 进行处理)" +
                "#wechat_redirect";
        response.setContentType("image/png");
        try {
            QrCodeUtil.generate(url,300,300,"jpg",response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

​ 打开页面localhost:8080/wx/official/auth,通过微信扫一扫进行扫码,点击确认接收

效果展示:

在这里插入图片描述

回调接口:

​ 如果用户点击同意或取消授权,页面将跳转至:

redirect_url/?openid=OPENID&template_id=TEMPLATE_ID&action=ACTION&scene=SCENE
参数:
参数说明
openid用户唯一标识,只在用户确认授权时才会带上
template_id订阅消息模板ID
action用户点击动作,"confirm"代表用户确认授权,"cancel"代表用户取消授权
scene订阅场景值
reserved请求带入原样返回
示例代码:
    public void getOfficialOpenid(Map<String, Object> params) {
        String openid = params.get("openid").toString();
        if (openid != null){
            saveOpenid(openid);
        }else {
            String action = "confirm".equals(params.get("action").toString()) ? "确定授权" : "取消授权";
            throw new RuntimeException("openid获取失败, 用户行为:" + action);
        }
    }
2)发送订阅消息
① 获取接口调用凭证

​ 获取方式如同 1.4.1节第三部分第一步。

② 推送订阅消息

​ 通过API推送订阅模板消息给到授权微信用户。

接口:
POST https://api.weixin.qq.com/cgi-bin/message/template/subscribe?access_token=ACCESS_TOKEN
Post参数:
参数是否必须说明
touser填接收消息的用户openid
template_id接口权限列表处订阅消息模板ID
url点击消息跳转的链接,需要有ICP备案
miniprogram跳小程序所需数据,不需跳小程序可不用传该数据
appid所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,并且小程序要求是已发布的)
pagepath所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar
scene订阅场景值
title消息标题,15字以内
data消息正文,value为消息内容文本(200字以内),没有固定格式,可用\n换行,color为整段消息内容的字体颜色(目前仅支持整段消息为一种颜色)

注:urlminiprogram都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。****

返回说明:
{
"errcode":0,
"errmsg":"ok"
}
示例代码:
    public void officialSendMessage() {
        String accessToken = getAccessToken(officialAppid, officialSecret);
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("touser", "用户openid");
        map.put("template_id", "接口权限列表处一次性订阅消息模板id");
        map.put("title", "阅读消息推送");
        map.put("scene", "0001");
        map.put("data", Collections.singletonMap("content", Collections.singletonMap("value", "文章制作不易,请留下一个小赞,谢谢。")));
        String resultJson = restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/message/template/subscribe?access_token=" + accessToken, map, String.class);
        Map result = JSONUtil.parseObj(resultJson).toBean(Map.class);
        if (Integer.parseInt(result.get("errcode").toString()) != 0){
            throw new RuntimeException("发送失败, 错误码:" + result.get("errcode") + " 错误信息:" + result.get("errmsg"));
        }
    }
效果展示:

在这里插入图片描述

2.2 模板消息

2.2.1 功能介绍

​ 模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。

​ 详情请见:微信官方文档-模板消息

2.2.2 前提条件

​ 一个已注册服务号,已备案域名。

​ 若没有注册服务号,也可以使用测试账户

​ 若没有备案域名,也可以使用免费Cpolar内网穿透工具

​ 本文使用已注册服务号进行演示。

2.2.3 准备工作

1)设置服务类目

​ 登录服务号账号后,点击设置与开发下的公众号设置,选择账号详情,找到服务类目,点击详情,进行设置。

在这里插入图片描述

2) 开通模板消息

​ 登录服务号账号后,点击**+ 新的功能**,找到 广告与服务中的模板消息 ,点击去开通,进行开通。

3)选择模板消息

​ 登录服务号账号后,点击广告与服务下的模板消息,选择模板库,选择模板。若没有贴合业务的模板,可点击右上角 帮助我们完善类目模板库,进行模板申请。
在这里插入图片描述

4)网页授权及业务域名配置

​ 登录服务号账号后,点击设置与开发下的公众号设置,选择功能设置,找到网页授权域名业务域名,点击设置,进行配置。

在这里插入图片描述

2.2.4 消息推送

1)获取并保存用户openid

​ 详情请见: 微信官方文档-网页授权

​ 引导用户在微信客户端打开网页授权页面,获取登录凭证。

接口:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

​ 若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

​ **尤其注意:**由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问。

参数:
参数是否必须说明
appid公众号的唯一标识
redirect_uri授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
response_type返回类型,请填写code
scope应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
state重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect无论直接打开还是做页面302重定向时候,必须带此参数
forcePopup强制此次授权需要用户弹窗确认;默认为false;需要注意的是,若用户命中了特殊场景下的静默授权逻辑,则此参数不生效

​ 下图为scope等于snsapi_userinfo时的授权页面:
在这里插入图片描述

示例代码:
  	// 这里通过生成二维码引导用户授权
 	public void officialRouter(HttpServletResponse response) {
        String redirectUrl = URLEncoder.encode("https://" + doMainName + "/wx/official/login");
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize" +
                "?appid=" + officialAppid +
                "&redirect_uri=" + redirectUrl +
                "&response_type=code" +
                "&scope=snsapi_base" +
                "&state=" + "0001" +
                "#wechat_redirect";
        response.setContentType("image/png");
        try {
            QrCodeUtil.generate(url,300,300,"jpg",response.getOutputStream());
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }
用户同意授权后

​ 如果用户同意授权,页面将跳转至

 redirect_uri/?code=CODE&state=STATE。

code说明:

code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

错误码:
返回码说明
10003redirect_uri域名与后台配置不一致
10004此公众号被封禁
10005此公众号并没有这些scope的权限
10006必须关注此测试号
10009操作太频繁了,请稍后重试
10010scope不能为空
10011redirect_uri不能为空
10012appid不能为空
10013state不能为空
10015公众号未授权第三方平台,请检查授权状态
10016不支持微信开放平台的Appid,请使用公众号Appid
示例代码:
    public void officialLogin(Map<String, Object> params) {
        RestTemplate restTemplate = new RestTemplate();
        String resultJson = restTemplate.getForObject("https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid=" + officialAppid +
                "&secret=" + officialSecret +
                "&code=" + params.get("code").toString() +
                "&grant_type=authorization_code", String.class).toString();
        Map result = JSONUtil.parseObj(resultJson).toBean(Map.class);
        if (result.get("openid") != null){
            saveOpenid(result.get("openid").toString());
        }else {
            throw new RuntimeException("openid获取失败, 错误码:" + result.get("errorcode") + "错误信息:" + result.get("errmsg"));
        }
    }
2)消息推送
接口:
POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
Post参数:
参数是否必填说明
touser接收者openid
template_id模板ID
url模板跳转链接(海外账号没有跳转能力)
miniprogram跳小程序所需数据,不需跳小程序可不用传该数据
appid所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)
pagepath所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏
data模板数据
client_msg_id防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效,超过10分钟不保证效果。若无防重入需求,可不填

注:urlminiprogram都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url

返回码说明
返回码含义
43116该模板因滥用被滥用过多,已被限制下发
40249不支持下发营销/推广类的消息内容
40250下发消息内容不规范(包含空值等),建议检查内容规范性后再下发
40251因历史违规导致平台限制账号调用上限,当前已到达下发上限
40252正在调用的模板下发的部分内容已进入平台审核流程,在审核完成前,相关内容暂时无法下发
其他说明:
参数类别参数说明参数值限制说明适用范围
thing.DATA事物20个以内字符可汉字、数字、字母或符号组合供姓名关键词、地址关键词、机构/组织名关键词选择(如:单位名、银行名、医院名、科室、班级)、品名关键词选择(如:药品名、股票名、课程名、科目名、岗位名)
character_string.DATA字符串32位以内数字、字母或符号可数字、字母或符号组合供数字/编码/编号/单号/卡号/航班号关键词选择(如:证券编码、设备编号、快递单号、银行卡号、网址)
time.DATA时间24小时制时间格式(支持+年月日),支持填时间段,两个时间点之间用“~”符号连接例如:15:01,或:2019年10月1日 15:01供时间类关键词选择
amount.DATA金额1个币种符号+12位以内纯数字,可带小数,结尾可带“元”可带小数供金额类关键词选择
phone_number.DATA电话17位以内,数字、符号电话号码,例:+86-0766-66888866供电话号码类关键词选择
car_number.DATA车牌8位以内,第一位与最后一位可为汉字,其余为字母或数字车牌号码:粤A8Z888挂供车牌号码类关键词选择
const.DATA常量20位以内字符,超过无法下发注:需枚举(需将内容提交平台审核,审核通过可下发)只能下发审核通过的字符串和空串供状态/方式/类型/提醒/说明/详情关键词选择(如:支付状态、排队状态、天气状态、物流状态、用药提醒、还款提醒)

​ 符号表示除中文、英文、数字外的常见符号,不能带有换行等控制字符。 时间格式支持HH:MM:SS或者HH:MM。 日期包含年月日,为y年m月d日,y年m月、m月d日格式,或者用‘-’、‘/’、‘.’符号连接,如2018-01-01,2018/01/01,2018.01.01,2018-01,01-01。 每个模板参数都会以类型为前缀,例如第一个数字模板参数为number01.DATA,第二个为number02.DATA

代码示例:
    public void officialTemplateSend() {
        String accessToken = getAccessToken(officialAppid, officialSecret);
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("touser", "用户openid");
        map.put("template_id", "公众号下模板消息的模板id");
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("thing3", Collections.singletonMap("value", "测试模板"));
        data.put("thing13", Collections.singletonMap("value", "张三"));
        data.put("thing6", Collections.singletonMap("value", "李四"));
        data.put("time5", Collections.singletonMap("value", "2024-07-30"));
        map.put("data", data);
        String resultJson = restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken, map, String.class);
        Map result = JSONUtil.toBean(resultJson, Map.class);
        if (0 != Integer.parseInt(result.get("errcode").toString())){
            throw new RuntimeException("发送失败, 错误码:" + result.get("errcode") + " 错误信息:" + result.get("errmsg"));
        }
    }
效果展示:

在这里插入图片描述

3. 后端代码仓库

​ 代码地址:微信消息推送后端演示代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值