前言
最近有微信公众号开发的业务,以前没有用python做过微信公众号开发,记录一下自己的学习和开发历程,共勉!
公众号类型
订阅号
普通订阅号
认证订阅号
服务号
普通服务号
认证服务号
服务方式
公众号消息会话:包括被动回复
公众号内嵌网页
公众号消息类型
群发消息:由公众号想用户发送消息;
被动回复消息:客户端发送消息,公众号回复;
客服消息:当用户主动发消息给公众号,公众号48小时里可以无限发送消息;
模板消息:使用特定的模板内容主动向用户发送消息;
公众号的网页接口
接口1:
网页被授权获取用户的基本信息,由微信提供接口;
接口2:
微型JS-SDK,用js代码使用原生的微信工具包;
微信公众号开发
先注册一个微信公众号
注册网址:https://mp.weixin.qq.com/cgi-bin/readtemplate?t=register/step1_tmpl&lang=zh_CN
进入注册网址后按相关步骤操作即可;
注册成功后会进入微信公众平台管理页面
登录后进入首页
进行公众号设置
包括头像,二维码,名称等;
可以设置微信号;
注意:
1.公众号类型一旦被选择就无法更改;
对接微信公众平台
填写服务器配置
URL:可以是域名网址或直接的ip加端口;http必须为80端口,https必须为443端口;
Token: 生成签名,微信服务器用来识别公众号服务器;
EncodingAESKey:设置消息加解密密匙;
验证服务器地址的有效性
开发者必须自己架设服务器,当填写URL提交后,微信服务器会发送get请求到开发者的服务器,携带四个参数,自定义返回echostr参数;
校验流程:
将token、timestamp、nonce三个参数进行字典序排序
将三个参数字符串拼接成一个字符串进行sha1加密
开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
- 校验的经典代码,适用于Django、Flask、web.py等框架;
import hashlib
# 在视图函数中
def handle(request):
try:
# 先获取request
# data = web.input()
# if len(data) == 0:
# return "hello, this is handle view"
signature = request.get("signature") # 先获取加密签名
timestamp = data.timestamp # 获取时间戳
nonce = request.get("nonece") # 获取随机数
echostr = request.get("echostr") # 获取随机字符串
token = "xxxx" #自己设置的token
# 使用字典序排序(按照字母或数字的大小顺序进行排序)
list = [token, timestamp, nonce]
list.sort()
# 进行sha1加密
temp = ''.join(list)
sha1 = hashlib.sha1(temp.encode('utf-8))
# map(sha1.update, list)
hashcode = sha1.hexdigest()
# 将加密后的字符串和signatrue对比,如果相同返回echostr,表示验证成功
if hashcode == signature:
return echostr
else:
return ""
except Exception as e:
return e
- 也可以通过第三方包wechatpy实现
from wechatpy.utils import check_signature
from flask import Flask
app = Flask(__name__)
def get_all_args(req_dict:Dict):
echostr = req_dict.get("echostr") # 获取随机字符串
signature = req_dict.get("signature") # 先获取加密签名
timestamp = req_dict.get("timestamp") # 获取时间戳
nonce = req_dict.get("nonce") # 获取随机数
return echostr,signature,timestamp,nonce
@app.route('/wechat_verify/',methods=['GET'])
def wechat_verify():
'''
用来处理微信服务器对本后台的验证,GET方法。
:return:
'''
# 获取参数
rq_dict = request.args
if len(rq_dict) == 0:
return ""
tuple_args = get_all_args(rq_dict)
token = current_app.config.get('TOKEN')
try:
check_signature(token, tuple_args[1], tuple_args[2], tuple_args[3])
except InvalidSignatureException as e:
logger.error(e,exc_info=True)
return ''
else:
return tuple_args[0]
根据接口实现业务逻辑
业务1:接收回复普通消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上,这时我们的公众号将覆盖微信提供的自动回复的功能;
- 微信消息的通信使用的是XMl的数据格式,在python中使用xmltodict模块处理xml的数据;主要有两个方法:
xmltodict.parse():可以将xml数据转为python中的dict字典数据;
xmltodict.unparse():可以将字典转换为xml字符串
- 文本消息
# 一般也有固定的格式
<xml>
<ToUserName><![CDATA[公众号]]></ToUserName> # 开发者微信号
<FromUserName><![CDATA[粉丝号]]></FromUserName> # 发送方微信号
<CreateTime>1460537339</CreateTime> # 消息的创建时间
<MsgType><![CDATA[text]]></MsgType> # 文本的格式
<Content><![CDATA[欢迎开启公众号开发者模式]]></Content> # 内容
<MsgId>6272960105994287618</MsgId> # 消息本身的id
</xml>
- 回复文本
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName> # 接收方账号
<FromUserName><![CDATA[fromUser]]></FromUserName> # 开发者账号
<CreateTime>12345678</CreateTime> # 创建时间
<MsgType><![CDATA[text]]></MsgType> # 文本类型
<Content><![CDATA[你好]]></Content> # 文本内容
</xml>
- 图片消息
<MsgType><![CDATA[image]]></MsgType> # 图片的类型为image
<PicUrl><![CDATA[this is a url]]></PicUrl> # 图片链接
<MediaId><![CDATA[media_id]]></MediaId> # 图片消息id
- 视频消息
<MsgType><![CDATA[video]]></MsgType> # 视频类型为video,小视频为shortvideo
- 语音消息
<MsgType><![CDATA[voice]]></MsgType> # 语音格式
<MediaId><![CDATA[media_id]]></MediaId> # 消息id
<Format><![CDATA[Format]]></Format> # 语音格式,如amr
视图处理原则
可以将普通的消息处理放置在一个视图中,在一个视图中进行判断处理,减少视图的数量。
如果不能再5秒内及时返回,可以先返回成功或空字符串,避免出现严重的错误。
实现内嵌网页
分成三步走:
- 第一步:用户同意授权,获取code,code指的是用户的授权书;这时有微信发起的;
- 第二步:通过code换取网页授权access_token,这时微信发下的通信证;
- 第三步:拉取用户信息(需scope为 snsapi_userinfo);
- 设置网页授权回调域名
注意
填写的是域名,而不是URL,所以不需要添加http://等;
可以填写IP和端口;
相关文档
获取微信公众号access_token接口凭证:url: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
获取微信IP地址:https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN
自定义菜单接口:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
总结:本篇博客是对开发微信公众号的一些整体需要做的准备工作和整体的认识,下一篇开始正式开发。