Python Tornado之搭建微信公众号接口验证和消息回复(三)

       第一篇,我们解决了测试公众号,第二篇我们简单的看了一下形目概况,下面就得一步一步写服务器了,同时别忘记我们还留了一个断点,那就是配置接口还未提交成功。强烈建议看 官网文档。其实后端服务器并不复杂,仅有一个路由,例如我的服务器中的/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 那么关于回复信息的就完成了,这个工作即使你没有认证订阅号,没花钱也能用。 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江湖人称王某人的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值