第一篇,我们解决了测试公众号,第二篇我们简单的看了一下形目概况,下面就得一步一步写服务器了,同时别忘记我们还留了一个断点,那就是配置接口还未提交成功。强烈建议看 官网文档。其实后端服务器并不复杂,仅有一个路由,例如我的服务器中的/start,start路由所指向的类有两种请求,get和post,get请求是来验证接口的,post是来处理客户的行为数据的。
一、写接口验证
自己写的微信公众号的后台比较有意思,它不是一个独立的服务器,不是直接和前端进行通信的,它需要和微信的服务器进行通讯,然后通过微信服务器与前台交互,也就是必须有微信服务器做中间器。因此有很多的接口和权限去调用和遵循,这个是最麻烦的事情,那么首先就是微信服务器对你后台的验证。还记得我们在注册测试号的时候,提交接口配置信息报错的事情吗?接口配置信息的url中间有wx,是因为我在ngnix做了反向代理,其实在后台的时候会被重写,说这个的意思是提醒大家url一定要写对。
1、上代码(节选,完整代码在 这篇博客)
import hashlib
import tornado.ioloop
import tornado.web
from tornado import httpserver
from wxlogger import logger # 自定义日志管理模块
class wxStartHandler(tornado.web.RequestHandler):
"""
微信服务器签名验证和消息回复
check_signature: 校验signature是否正确
"""
def check_signature(self, signature, timestamp, nonce):
"""校验token是否正确"""
# 这个是token 和我们在微信公众平台配置接口填写一致
token = 'iotbird'
L = [timestamp, nonce, token]
L.sort()
s = L[0] + L[1] + L[2]
sha1 = hashlib.sha1(s.encode('utf-8')).hexdigest()
# 对于验证结果返回true or false
return sha1 == signature
#
def get(self):
"""这是get请求,处理配置接口验证的"""
try:
# 获取参数
signature = self.get_argument('signature')
timestamp = self.get_argument('timestamp')
nonce = self.get_argument('nonce')
echostr = self.get_argument('echostr')
# 调用验证函数
result = self.check_signature(signature, timestamp, nonce)
if result:
self.write(echostr)
else:
logger.error('微信sign校验,---校验失败')
except Exception as e:
logger.error('wxhandler get'+str(e))
def main():
application = tornado.web.Application([
(r'/start', wxStartHandler), # 验证配置接口和消息回复路由
],
autoreload=False,
debug=False
)
#application.listen(9000) #http服务器开启
# 下面代码是配置https服务器,当然选用http服务器也是可以的
server = httpserver.HTTPServer(application, ssl_options={
"certfile":"server.crt",
"keyfile": "server.key",
}
)
server.listen(9000)# 单进程开启
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
重点观察路由,我们运行此文件然后提交配置信息,发现就成功了
二、写消息回复路由
之前说过,这个信息回复权限大家都有,很多人就自己做出智能机器人了,只要我们能拿到客户发的数据,当然很简单啦
1、上代码(节选,完整代码在 这篇博客)
# wxreply文件是我写关于处理回复的函数,我们导出来必要的函数
from wxreply import receive_msg,receive_event,reply_text
class wxStartHandler(tornado.web.RequestHandler):
"""
微信服务器签名验证和消息回复
check_signature: 校验signature是否正确
"""
def post(self):
""" 这是post请求 接收消息,获取参数 """
body = self.request.body
# 返回的bodys是xml格式,通过ET转换为键值对格式,方便提取信息
data = ET.fromstring(body)
ToUserName = data.find('ToUserName').text
FromUserName = data.find('FromUserName').text
MsgType = data.find('MsgType').text
# 如果发送的是消息请求,判断是文字还是语音,因为我们取发送的内容位置不一样
if MsgType == 'text' or MsgType == 'voice':
try:
MsgId = data.find("MsgId").text
if MsgType == 'text':
Content = data.find('Content').text # 文本消息内容
elif MsgType == 'voice':
Content = data.find('Recognition').text # 语音识别结果,UTF8编码
# 调用回复函数判断接受的信息,然后返回对应的内容
reply_content=receive_msg(Content)
CreateTime = int(time.time())
# 调用回复信息封装函数,要指定用户,时间和回复内容
out = reply_text(FromUserName, ToUserName, CreateTime, reply_content)
self.write(out)
except Exception as e:
logger.error('wxStartHandler post'+str(e))
# 如果接收的是事件,我们也要处理
elif MsgType == 'event':
try:
Event = data.find('Event').text
Event_key = data.find('EventKey').text
CreateTime = int(time.time())
# 判断事件,并返回内容
reply_content = receive_event(Event,Event_key)
if reply_content:
out = reply_text(FromUserName, ToUserName, CreateTime, reply_content)
self.write(out)
except Exception as e:
logger.error('wxStartHandler post'+str(e))
from wxlogger import logger
"""这是一个处理客户发送信息的文件"""
def reply_text(FromUserName, ToUserName, CreateTime, Content):
"""回复文本消息模板"""
textTpl = """<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content></xml>"""
out = textTpl % (FromUserName, ToUserName, CreateTime, 'text', Content)
return out
def receive_msg(msg):
# 这是一个将疑问改成成熟句子的函数,例如:你好吗 公众号回复:你好
if msg[-1] == u'吗':
return msg[:len(msg)-1]
elif len(msg)>2 and msg[-2] == u'吗' :
return msg[:len(msg)-2]
else:
return "你说的话我好像不明白?"
def receive_event(event,key):
# 如果是关注公众号事件
if event == 'subscribe':
return "感谢关注!"
# 如果是点击菜单拉取消息事件
elif event == 'CLICK':
# 接下来就是根据你点击不同的菜单拉去不同的消息啦
# 我为了省事,不进行判断啦,如果需要判断请根据 key进行判断
return "你点击了菜单"+key
# 如果是点击菜单跳转Url事件,不做任何处理因为微信客户端会自行处理
elif event == 'VIEW':
return None
main.py文件还是那个文件 完整看这里 完整代码在 这篇博客
2、上微信消息包结构,我们只关注文本消息和语音消息
这个很容易理解吧,我们运行服务器走一波
关注测试号,根据我们所写的回复函数,会回复:感谢关注!
发送信息和测试语音
OK 那么关于回复信息的就完成了,这个工作即使你没有认证订阅号,没花钱也能用。