当普通用户想公众号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
微信的可以收到用户的消息类型分文本、图片、语言、视频、小视频、地理位置和链接,所对应的MsgType分别为[text,image,voice,video,shortvideo,location,link]。
请注意:
1、关于重试的消息排重,推荐使用msgid排重。
2、微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,
可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息”。
3、如果开发者需要对用户消息在5秒内立即做出回应,即使用“发送消息-被动回复消息”接口向用户被动回复消息时,可以在
公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息和开发者回复的消息都会被加密(但开发者通过客服
接口等API调用形式向用户发送消息,则不受影响)。关于消息加解密的详细说明,请见“发送消息-被动回复消息加解密说明”。
微信收到的消息类型结构
微信被动回复的消息类型结构
我们以微信的文本消息类型做为列子说明。
首先我们来看看文本消息的XML结构个说明
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1348831860CreateTime>
<MsgType>MsgType>
<Content>Content>
<MsgId>1234567890123456MsgId>
xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | text |
Content | 文本消息内容 |
MsgId 消息id | 64位整型 |
由于POST过来的是XML类型我数据,所以我们首要做的就是做xml解析。Python中自带了xml解析模块了。就直接导入进行解析
import xml.etree.cElementTree as et
xmldata = '''<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>1348831860CreateTime>
<MsgType>MsgType>
<Content>Content>
<MsgId>1234567890123456MsgId>
xml>'''
xml_rec = et.fromstring(xmldata)
ToUserName = xml_rec.find('ToUserName').text
fromUser = xml_rec.find('FromUserName').text
MsgType = xml_rec.find('MsgType').text
Content = xml_rec.find('Content').text
MsgId = xml_rec.find('MsgId').text
print(ToUserName, fromUser ,MsgType ,Content, MsgId)
打印结果
toUser fromUser text this is a test 1234567890123456
解析了xml之后,我们就要给用户回消息。我们回复的消息也是xml类型
<xml>
<ToUserName>ToUserName>
<FromUserName>FromUserName>
<CreateTime>12345678CreateTime>
<MsgType>MsgType>
<Content>Content>
xml>
参数 | 是否必须 | 描述 |
---|---|---|
ToUserName | 是 | 接收方帐号(收到的OpenID) |
FromUserName | 是 | 开发者微信号 |
CreateTime | 是 | 消息创建时间 (整型) |
MsgType | 是 | text |
Content | 是 | 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示) |
回复消息的时候需要注意一点,就是我们回复给用户的ToUserName和FromUserName和接收到的应该是相反的,就是邮件的发送一样。
新建一个muban.py
text_str = '''
![CDATA[%s]]
![CDATA[%s]]
%s
![CDATA[text]]
![CDATA[%s]]
'''
def reply_muban(type):
if type == 'text':
return text_str
打开我们之前的main.py,导入模板,添加xml解析代码和返回代码,由于是POST过来的,所以我们需要做POST判断
# -*- coding:utf-8 -*-
from flask import Flask,request
from time import time
import xml.etree.ElementTree as et
import muban
import hashlib
app = Flask(__name__)
app.debug = True
@app.route('/wx_flask',methods=['GET','POST'])
def wechat():
if request.method == 'GET':
token = 'xiaoqingxin'
data = request.args
signature = data.get('signature','')
timestamp = data.get('timestamp','')
nonce = data.get('nonce','')
echostr = data.get('echostr','')
list = [token, timestamp, nonce]
list.sort()
s = list[0] + list[1] + list[2]
hascode = hashlib.sha1(s.encode('utf-8')).hexdigest()
if hascode == signature:
return echostr
else:
return ""
if request.method == 'POST':
xmldata = request.args
xml_rec = et.fromstring(xmldata)
ToUserName = xml_rec.find('ToUserName').text
fromUser = xml_rec.find('FromUserName').text
MsgType = xml_rec.find('MsgType').text
Content = xml_rec.find('Content').text
MsgId = xml_rec.find('MsgId').text
return muban.reply_muban(MsgType) % (fromUser, ToUserName, int(time()), Content)
if __name__ == '__main__':
app.run()
可以看到我这里还有其他的回复,我把代码贴下,和文本回复差不多。
muban.py
# -*- coding:utf-8 -*-
text_str = "<xml><ToUserName>ToUserName><FromUserName>FromUserName><CreateTime>%sCreateTime><MsgType>MsgType><Content>Content>xml>"
img_str = "<xml><ToUserName>ToUserName><FromUserName>FromUserName><CreateTime>%sCreateTime><MsgType>MsgType><Image><MediaId>MediaId>Image>xml>"
image_text_lj = "<ArticleCount>%sArticleCount><Articles>%sArticles>xml>"
image_text_item = "<item><Title>Title><Description>Description><PicUrl>PicUrl><Url>Url>item>"
def reply_muban(type):
if type == "text":
return text_str
elif type == "image":
return img_str
def image_text_new_muban(itemDic):
items = ""
for item in itemDic:
items += image_text_item % (item['Title'], item['Description'], item['PicUrl'], item['Url'])
return image_text_str + (image_text_lj % (len(itemDic), items))
main.py
if request.method == 'POST':
str_xml = request.stream.read()
xml = etree.fromstring(str_xml)
msgType = xml.find("MsgType").text
xml_muban = muban.reply_muban(msgType)
if msgType == "text":
content = xml.find("Content").text
fromUser = xml.find("FromUserName").text
toUser = xml.find("ToUserName").text
return xml_muban % (fromUser, toUser, int(time()), content)
elif msgType == "image":
fromUser = xml.find("FromUserName").text
toUser = xml.find("ToUserName").text
mediaid = xml.find("MediaId").text
print(xml_muban % (fromUser, toUser, int(time()), mediaid))
return xml_muban % (fromUser, toUser, int(time()), mediaid)
else:
itemDic = [{'Title':'Title','Description':'Description',
'PicUrl':'https://ss0.baidu.com/73x1bjeh1BF3odCf/it/u=3705265267,3767781981&fm=85&s=DE0A5C2A7D264E1B62FD99CB0300C0B1',
'Url':'www.baidu.com'},{'Title':'Title1','Description':'Description1',
'PicUrl':'https://ss0.baidu.com/73x1bjeh1BF3odCf/it/u=3705265267,3767781981&fm=85&s=DE0A5C2A7D264E1B62FD99CB0300C0B1',
'Url':'www.baidu.com'}]
fromUser = xml.find("FromUserName").text
toUser = xml.find("ToUserName").text
mediaid = xml.find("MediaId").text
return muban.image_text_new_muban(itemDic) % (fromUser, toUser, int(time()))
if __name__ == '__main__':
app.run()
微信收到的消息类型结构
微信被动回复的消息类型结构