上次我们已经完成了微信公众号开发环境的搭建,并完成了服务器和微信公众号的校验。下面让我们来开始实际开发。
如果还没有微信公众号开发环境的,请参考我上一篇文章:
本篇文章的内容为带领大家打通用户与服务器的信息交流通道:用户发的消息能在服务器收到,服务器能回复消息给用户。
0. 准备工作
0.1 代码修改
昨天的代码只是完成了微信公众号和服务器的校验,并没有地方处理用户的消息,下面我们来加上。
#!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask, request import hashlib app = Flask(__name__) ##### 修改1:将昨天的校验代码封装成单独的函数 ##### def verify_wechat(request): # 设置token,开发者配置中心使用 token = 'xxxxx' # <------ 替换成你自定义的Token # 获取微信服务器发送过来的参数 data = request.args signature = data.get('signature') timestamp = data.get('timestamp') nonce = data.get('nonce') echostr = data.get('echostr') # 对参数进行字典排序,拼接字符串 temp = [timestamp, nonce, token] temp.sort() temp = ''.join(temp) # 加密 if (hashlib.sha1(temp.encode('utf8')).hexdigest() == signature): return echostr else: return 'error', 403 ##### 修改2:将服务访问路径由昨天的'/'换成'/wechatai' ##### ##### 这里也可以不换路径,名字也可以你自己随意定 ##### @app.route('/wechatai', methods=['GET', 'POST']) def wechatai(): ##### 修改3:当接受到的消息为GET请求时,执行校验,如果为POST请求,则认为是用户消息,处理用户消息 if request.method == 'GET': return verify_wechat(request) else: # 处理POST请求 print("user request data: ", request.data) return "ok" # <--------- 一定要加返回值! if __name__ == '__main__': app.run(host='0.0.0.0', port=80, debug=True)
如果你执行了上面的“修改2”,将访问路径改了,那需要到公众号里对服务器配置进行相应的修改,即在URL后面也加入这个路径,这样才能访问到。
0.2 启用服务器
- 首先确保完成了上面的环境搭建和校验成功。
- 确保你的程序已经开始运行
在配置服务器的公众号后台 —> “服务器配置” —> 点击“启用”
这样就相当于与咱们的服务器打通了,用户发的消息都会被微信服务器转发到咱们自己的服务上去,咱们就可以在自己的服务器上处理消息了。
1. 发个消息试试
首先你得关注这个公众号
1.1 发个消息试试
(1)打开这个公众号页面,发送消息“test”
(2)去服务器上查看你的程序收到的消息
如果正常,你应该能在你的程序运行后台看到下面的信息。这一坨数据下文我会解释其意思,这里你先能收到它就OK了。
1.2 可能遇到的坑(我遇到的)
(1)服务器收不到用户消息:校验成功,但是用户发的消息服务器看不到。
- 网上的解决方案:
微信公众号可以验证后台服务器(get),但却接收不到微信用户的消息及事件通知的一个可能性
- 我的解决方案:以上解决方案并不能解决我的问题,我是在启用服务器的状态下,重新配置了一下服务器配置,然后就神奇的好了…
2. 用户消息处理
2.1 用户消息内容
下面我们来看下服务收到的用户消息内容:
b'<xml><ToUserName><![CDATA[gh_fa8fa31]]></ToUserName>\n<FromUserName><![CDATA[oNexy6R4Ubm8gUCr1U]]></FromUserName>\n<CreateTime>1704420739</CreateTime>\n<MsgType><![CDATA[text]]></MsgType>\n<Content><![CDATA[test]]></Content>\n<MsgId>244014308074</MsgId>\n</xml>'
可以看到这是一个xml格式的字符串。用Python将以上xml字符串格式化打印出来,格式化打印xml字符串内容的代码如下:
import xml.etree.ElementTree as ET def printXML(xml_content): # 创建XML元素 element = ET.XML(xml_content) # 使用indent()函数进行格式化打印 ET.indent(element) print(ET.tostring(element, encoding='unicode'))
调用函数打印:
python printXML(request.data)
打印如下:
<xml> <ToUserName>gh_fa8fa31e</ToUserName> <FromUserName>oNexy6R49UkCr1U</FromUserName> <CreateTime>1704424380</CreateTime> <MsgType>text</MsgType> <Content>test</Content> <MsgId>244099103</MsgId> </xml>
这是一个text类型的消息,内容是test。知道用户消息的内容结构之后,现在我们就可以提取出里面的Content来做一些相应的处理了,比如回复用户消息。
2.2 用户消息解析
先来提取用户消息中的Content内容,也就是用户发过来的文字:
(1)定义提取函数
def getUserMessageContentFromXML(xml_content): # 解析XML字符串 root = ET.fromstring(xml_content) # 提取数据 content = root.find('Content').text from_user_name = root.find('FromUserName').text to_user_name = root.find('ToUserName').text return content, from_user_name, to_user_name
(2)调用提取函数
@app.route('/wechatai', methods=['GET', 'POST']) def wechatai(): if request.method == 'GET': return verify_wechat(request) else: # 处理POST请求 print("user request data: ", request.data) printXML(request.data) user_message_content, from_user_name, to_user_name = getUserMessageContentFromXML(request.data) # <--------- 这里这里这里 print("user message content: ", user_message_content) return "ok"
重新运行程序,用户发送过来消息后,应该能解析出结果如下:
3. 给用户回消息
上面我们能收到用户的消息,解析出用户发送的内容。但是如何给用户回消息呢?上面函数有一个 return "ok"
,但这只是给微信服务器回的消息,并不是给用户回的消息。
其实给用户回消息很简单,只需要将上面接收到的xml字符串,改一下里面的值即可。
(1)封装一个函数用来生成给回复的xml字符串
def generate_response_xml(from_user_name, to_user_name, output_content): # 1. 先准备好回复的xml格式,后面只需要填充里面的字段即可 output_xml = ''' <xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[%s]]></Content> </xml>''' # 2. 通过 make_response 函数封装网络返回结构体 response = make_response(output_xml % (from_user_name, to_user_name, str(int(time.time())), output_content)) response.content_type = 'application/xml' return response
可以看到,xml的内容与接收到的基本一致,我们只需要填充里面的ToUserName
、FromUserName
、CreateTime
、Content
即可。
ToUserName
、FromUserName
:与接收到的xml保持一致CreateTime
:当前时间戳Content
:要回复给用户的内容
(2)调用函数生成回复内容的结构
@app.route('/wechatai', methods=['GET', 'POST']) def wechatai(): if request.method == 'GET': return verify_wechat(request) else: # 处理POST请求 print("user request data: ", request.data) printXML(request.data) user_message_content, from_user_name, to_user_name = getUserMessageContentFromXML(request.data) print("user message content: ", user_message_content) return generate_response_xml(from_user_name, to_user_name, "你好") # <------ 这一句代码!给用户回复一个“你好”
重新运行程序,用户发送过来消息后,在微信公众号用户对话界面,用户应该能收到“你好”的消息。
至此,我们已经打通了用户与服务器的信息交流通道,后面就是在服务器端加自己的业务逻辑了。
从今天开始,持续学习,开始搞事情。踩坑不易,欢迎关注我,围观我!
有任何问题,一起讨论,共同进步!