最近在用sanic框架写微信小程序,其中写了一个微信消息推送,还挺有意思的,写了个小demo
具体见官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
文档其实写的很详细清除了,包括返回数据的类型,报错信息
大致流程就是:调用微信小程序的接口,获取access_token,然后再调用发送模板信息的接口,发送消息
获取access_token
access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。------>我们后台可以用edis存储,然后定时任务,2小时失效
获取access_token调用接口:
#https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
#参数说明 #参数 是否必须 说明 grant_type 是 获取access_token填写client_credential appid 是 第三方用户唯一凭证 secret 是 第三方用户唯一凭证密钥,即appsecret #返回说明 #正常情况下,微信会返回下述JSON数据包给公众号: {"access_token":"ACCESS_TOKEN","expires_in":7200} #参数说明 #参数 说明 access_token 获取到的凭证 expires_in 凭证有效时间,单位:秒 #错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误): {"errcode":40013,"errmsg":"invalid appid"} #返回码说明 #返回码 说明 -1 系统繁忙,此时请开发者稍候再试 0 请求成功 40001 AppSecret错误或者AppSecret不属于这个公众号,请开发者确认AppSecret的正确性 40002 请确保grant_type字段值为client_credential 40164 调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)
发送模板信息请求地址
POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
#参数 string access_token #接口调用凭证:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183 string touser #接收者(用户)的 openid string template_id #所需下发的模板消息的id string page #点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 string form_id #表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id string data #模板内容,不填则下发空模板 string emphasis_keyword #模板需要放大的关键词,不填则默认无放大
接口判断返回值
#返回值 #Object #返回的 JSON 数据包 #属性 类型 说明 支持版本 errcode number 错误码 errmsg string 错误信息 errcode 的合法值 #值 说明 40037 template_id不正确 41028 form_id不正确,或者过期 41029 form_id已被使用 41030 page不正确 45009 接口调用超过限额(目前默认每个帐号日调用限额为100万) POST 数据格式:JSON #请求数据示例 { "touser": "OPENID", "template_id": "TEMPLATE_ID", "page": "index", "form_id": "FORMID", "data": { "keyword1": { "value": "339208499" }, "keyword2": { "value": "2015年01月05日 12:30" }, "keyword3": { "value": "腾讯微信总部" } , "keyword4": { "value": "广州市海珠区新港中路397号" } }, "emphasis_keyword": "keyword1.DATA" } #返回数据示例 { "errcode": 0, "errmsg": "ok", "template_id": "wDYzYZVxobJivW9oMpSCpuvACOfJXQIoKUm0PY397Tc" }
全部代码展示
这里面有个特别的参数是
string form_id
表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
如果想钻空子,如果服务端想主动发送模板消息,可以提前手机formId
构建formId 池,每次将用户提交的表单都搜集起来存入formId池,需要发送通知的时候从中取出即可。
将用户有可能点击的区域覆盖一层不可见的button,并将整个页面用于传输formId的button包裹在一Form标签内,一旦用户有点击按钮的操作,就将获取到的formId传送走。
import requests import json as osjson import configparser from Model.RedisDB import VideoData _cf = configparser.ConfigParser() _cf.read("/septnet/config/ServerConf_V2.conf") # 获取微信access_token async def get_access_token(): try: payload = { \'grant_type\': \'client_credential\', \'appid\': _cf.get("wechat","APPID"), \'secret\': _cf.get("wechat","APPSECRET") } req = requests.get(\'https://api.weixin.qq.com/cgi-bin/token\', params=payload, timeout=3, verify=False) access_token = req.json().get(\'access_token\',"") print(\'access_token\', access_token) return access_token except Exception as e: print(e) # 发送模板消息 def template_push(openid,form_id,date,access_token): data = { "touser": openid, "template_id": _cf.get("wechat","TEMPLATE_ID"), "form_id": form_id, \'page\': \'pages/selectDetail/selectDetail?chooseSubjectTaskId=5b8de9ac705deb7cfa927abc\', "data": { \'keyword1\': { \'value\': date }, \'keyword2\': { \'value\': \'收到消息请尽快进入小程序中接收视频邀请,在2分钟内如未进行操作,视频无法成功接通,需对方再次重新发起视频邀请\' } }, "emphasis_keyword": \'\' } push_url = \'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={}\'.format(access_token) result = requests.post(push_url, json=data, timeout=3, verify=False) return result # 发送视频通话模板消息 async def sendTemplateMessage(key,openid, form_id, date): req=await VideoData.get(key) if not req: access_token=get_access_token() if not access_token: return False try: req_push=template_push(openid, form_id, date, access_token) req_redis = await VideoData.set(key,access_token,ex=2*60*60) if not req_redis: return False errcode = req_push.json().get("errcode") if errcode==0: return True return False except Exception as e: print(e) access_token = osjson.loads(req) template_push(openid, form_id, date, access_token) return True