微信系列之公眾號被動消息回復


微信系列之公眾號被動消息回復

基於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__()

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM