微信系列之公众号被动消息回复

微信系列之公众号被动消息回复

基于Flask和Jinja2开发


被动消息回复

回复success问题

查询官方wiki 开头强调: 假如服务器无法保证在五秒内处理回复,则必须回复“success”或者“”(空串),否则微信后台会发起三次重试。
解释一下为何有这么奇怪的规定。发起重试是微信后台为了尽可以保证粉丝发送的内容开发者均可以收到。如果开发者不进行回复,微信后台没办法确认开发者已收到消息,只好重试。

微信公众号开发的消息类型共7类
1.文本
2.图片
3.语音
4.视频
5.小视频
6.地理位置
7.链接

不同的消息类型其模板各有不同,但共同的模板都包括

参数 描述
ToUserName 接收者微信号
FromUserName 发送者微信号,若为普通用户,则为OpenID
CreateTime 消息创建时间,时间戳格式
MsgType 消息类型
MegId 消息id, 64位整形

如下所示

{# base.xml #}
<xml>
<ToUserName><![CDATA[{{ ToUserName }}]]></ToUserName>
<FromUserName><![CDATA[{{ FromUserName }}]]></FromUserName>
<CreateTime>{{ CreateTime }}</CreateTime>
<MsgType><![CDATA[{{ MsgType }}]]></MsgType>
{% block Message %}{% endblock %}
</xml>

信息接收过程基本解析

1.后台接收微信post提交的数据,需要注意的是,微信对url的规定很严格。如果服务器配置的反斜杠/结尾,则微信配置的url也要添加反斜杠,否则会出现301重定向错误。
2.进行数据解析,如果没有适合的数据解析方法,则响应success或者空字符
3.响应特定的数据类型


文本消息

{# text.xml #}
{% extends "base.xml" %}
{% block Message %}
<Content><![CDATA[{{ Content }}]]></Content>
{% endblock %}

图片消息

微信公众号官方文档说明 MediaId 可用来标记特定临时图片,可填写临时MediaId或者永久的MediaId

{# image.xml #}
{% extends "base.xml" %}
{% block Message %}
 <Image>
 <MediaId><![CDATA[{{ MediaId }}]]></MediaId>
 </Image>
 </xml>
{% endblock %}

完整代码

# coding: utf-8
# package_name: wx_mp
# 微信公众号入口
from flask import Blueprint
from flask import request
from wx_mp import receive
from wx_mp import replay
import hashlib
mp = Blueprint('wx_mp', __name__)


def token_check():
    signature = request.args.get("signature", '')
    timestamp = request.args.get('timestamp', '')
    echostr = request.args.get("echostr", '')
    nonce = request.args.get("nonce", '')
    token = "******"
    check_list = [nonce, timestamp, token]
    check_list.sort()  # 对列表进行非序
    sha1 = hashlib.sha1()
    list(map(lambda x: sha1.update(x.encode('utf-8')), check_list))
    hashcode = sha1.hexdigest()
    if signature == hashcode:
        return echostr
    return ''


def wx_get():
    if len(request.args) == 0:
        # 无参数,普通请求,直接返回
        return "This wechat view"
    return token_check()


def wx_post():
    recMsg = receive.parse_xml()
    replayMsg = replay.get_replay(recMsg)
    return replayMsg


@mp.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return wx_get()
    elif request.method == 'POST':
        return wx_post()

# coding: utf-8
# filename: receive.py
# 解析微信发来的消息
from flask import request
from lxml import etree


class Msg(object):
    def __init__(self, xml_data):
        self.ToUserName = xml_data.xpath('//ToUserName/text()')[0]
        self.FromUserName = xml_data.xpath('//FromUserName/text()')[0]
        self.MsgType = xml_data.xpath('//MsgType/text()')[0]
        self.MsgId = xml_data.xpath('//MsgId/text()')[0]
        self.CreateTime = xml_data.xpath('//CreateTime/text()')[0]


class TextMsg(Msg):
    def __init__(self, xml_data):
        super().__init__(xml_data)
        self.Content = xml_data.xpath('//Content/text()')[0]


class ImageMsg(Msg):
    def __init__(self, xml_data):
        super().__init__(xml_data)
        self.PicUrl = xml_data.xpath('//PicUrl/text()')[0]
        self.MediaId = xml_data.xpath('//MediaId/text()')[0]


def parse_xml():
    xml_data = etree.XML(request.data)
    msg_type = xml_data.xpath('//MsgType/text()')[0]
    if msg_type == 'text':
        recMsg = TextMsg(xml_data)
    elif msg_type == 'image':
        recMsg = ImageMsg(xml_data)
    return recMsg
# coding: utf-8
# filename: replay.py
# 发送消息给用户
from wx_mp import receive
from time import time
from flask import render_template


class Msg(object):
    def __init__(self, recMsg):
        self.ToUserName = recMsg.FromUserName
        self.FromUserName = recMsg.ToUserName
        self.CreateTime = int(time())

    def send(self):
        return 'success'


class TextMsg(Msg):
    def __init__(self, recMsg):
        super().__init__(recMsg)
        self.MsgType = 'text'
        self.Content = '测试文本'

    def send(self):
        return render_template('text.xml', **self.__dict__)


class ImageMsg(Msg):
    def __init__(self, recMsg):
        super().__init__(recMsg)
        self.MsgType = 'image'
        self.MediaId = recMsg.MediaId

    def send(self):
        print(self.__dict__)
        return render_template('image.xml', **self.__dict__)


def get_replay(recMsg):
    try:
        if isinstance(recMsg, receive.Msg):
            if recMsg.MsgType == 'text':
                replayMsg = TextMsg(recMsg)
            elif recMsg.MsgType == 'image':
                replayMsg = ImageMsg(recMsg)
            return replayMsg.send()

        else:
            return Msg.send()
    except Exception as e:
        return e.__repr__()

参考资料

posted @ 2019-03-09 21:16  朝行  阅读(1769)  评论(0编辑  收藏  举报