在SAE上搭建微信公众平台账号消息服务器

利用微信公众平台提供的消息接口,搭建自己的消息处理服务器,消息的处理和回复将更加灵活,以期给订阅用户提供更加定制化和个性化的信息。本文将结合SAE,基于Python Flask框架,搭建一个公众账号“豆米查书”(微信号doumibook)的消息服务器。该公众号的基本功能是:输入书籍标题、作者或者isbn条码号等关键字,查询书籍的基本信息。书籍数据来源豆瓣网,使用了douban api v2

一、申请微信公众平台账号

这里注册微信公众平台账号,登陆,设置必要的名称、地区和用户信息等内容。在“高级功能”中开启“开发模式”。

仔细阅读微信公众平台的官方文档

二、在SAE上创建Python应用

创建Python应用,二级域名和应用名称为doumibook,那么基本地址为http://doumibook.sinaapp.com。

三、申请消息接口并验证

1,消息接口配置

到“高级功能”-->“开发模式”-->“成为开发者”中填写接口配置信息,有URL和Token,URL用于接口验证和消息推送,本例中填写步骤二中的接入地址,Token用于接口验证,任意填写即可,例如填写“doumitest”。

2,消息接口验证(网址接入)

信息填写完成后,点击提交,会提示认证“服务器未正确响应的Token验证”,这是正常的,因为我们虽然创建了SAE应用,但没有处理接口验证消息。点击提交时,微信服务器会发送一条Http GET请求,携带signature、timestamp、nouce和echostr四个参数,对URL进行合法性的校验(参考微信官方的详细文档的“网址接入”小节)。如下是flask中处理接口验证的代码:

import hashlib
 
 @app.route('/weixin', methods=['GET'])
 def weixin_verify():
     signature = request.args.get('signature')
     timestamp = request.args.get('timestamp')
     nonce = request.args.get('nonce')
     echostr = request.args.get('echostr')
     
     token = 'doumitest' #和申请消息接口时的Token一致
     tmplist = [token, timestamp, nonce]
     tmplist.sort()
     tmpstr = ''.join(tmplist)
     hashstr = hashlib.sha1(tmpstr).hexdigest()
 
     if hashstr == signature:
         return echostr #success
     return 'access verification fail' #fail

 

四、消息推送和消息回复

1,消息推送

URL接口验证以后,公众平台账号收到的消息将由微信服务器使用HTTP POST推送至该URL。消息内容为XML格式,消息类型有文本、图片和地理位置等,例如文本消息由以下几个部分组成。

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[this is a test]]></Content>
</xml>

其中,ToUserName和FromUserName分别为公众帐号和用户帐号的表识串。MsgType标识消息类型,“text”表明消息是文本消息,文本内容放置在Content字段。其他类型消息的xml结构请参照官方文档。

使用下面的代码片段,解析xml数据,以dict形式保存:

import xml.etree.ElementTree as ET
 
 def parse_msg(rawmsgstr):
     root = ET.fromstring(rawmsgstr)
     msg = {}
     for child in root:
         msg[child.tag] = child.text
     return msg

 

2,用户订阅消息

当有新用户关注公众号时,微信服务器会发送一条通知消息到消息服务器,消息服务器可以返回初次订阅的欢迎和帮助信息。目前,微信启用了新的用户订阅通知方法,即使用事件推送。

事件推送的MsgType为“event”,是微信4.5版开始支持的一种消息格式,可以发送用户订阅( subscribe)、退订(unsubscribe)以及自定义菜单点击(CLICK)等事件消息。消息格式为:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[EVENT]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>

微信官方已经发布通告,在2013年3月26日起由原来的发送一条内容为“Hello2BizUser”的订阅消息,切换至事件推送方法。

 

3,书籍信息获取

简单起见,目前仅支持微信用户发送书籍isbn条码号给doumibook,来查询作者和书名。使用douban api v2版接口,获取书籍信息,douban返回的json数据。代码片段如下:

 import urllib2
 import json
 
 bookurlbase = 'http://api.douban.com/v2/book/isbn/'
 DOUBAN_APIKEY = '' #豆瓣上申请的APIKEY
 
 def query_book_info(isbn):
     url = '%s%s?apikey=%s' % (bookurlbase, isbn, DOUBAN_APIKEY)
     resp = urllib2.urlopen(url)
     book = json.loads(resp.read())
     info = ''.join(book['author']) + ': ' + book['title']
     return info

 

4,消息回复

查询到书籍信息之后,消息服务器响应微信服务器的消息推送,回复内容结构同样是XML,假设我们回复文本消息,基本结构如下:

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>12345678</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[content]]></Content>
  <FuncFlag>0</FuncFlag>
 </xml>

其中的ToUserName和FromUserName与消息推送中的相关。

构造回复消息代码片段如下:

def response_msg(recvmsg, content):
     textTpl = """<xml>
             <ToUserName><![CDATA[%s]]></ToUserName>
             <FromUserName><![CDATA[%s]]></FromUserName>
             <CreateTime>%s</CreateTime>
             <MsgType><![CDATA[%s]]></MsgType>
             <Content><![CDATA[%s]]></Content>
             <FuncFlag>0</FuncFlag>
             </xml>"""
     echostr = textTpl % (recvmsg['FromUserName'], recvmsg['ToUserName'], recvmsg['CreateTime'], recvmsg['MsgType'], content)
     return echostr

 注意到,回复文本消息,内容比较单一,这里可以使用MsgType为“news”的图文消息格式进行回复,这里不再赘述,请参考官方文档以及本文末尾给出的源代码链接。

4,综合

消息推送HTTP POST请求的处理代码如下:

 @app.route('/weixin', methods=['POST'])
 def weixin_msg():
     data = request.data
     msg = parse_msg(data)
     content = 'not found'
     if msg.has_key('Content'):
         content = query_book_info(msg['Content'])
     return response_msg(msg, content)

 

五、总结

本文以doumibook为例,使用Python Flask框架,介绍了在SAE上搭建微信公众平台账号消息服务器的基本步骤。

需要看完整代码的同学,请移步这里:https://github.com/gzb1985/doumibook_weixin

doumibook目前仅实现了很简单的功能,还没有实用的价值,例如输入“浪潮之巅”,则返回:

仅供参考,抛砖引玉吧。

 

文章更新记录:

2013.3.31:微信官方公布的新的用户订阅消息方法,见四(2)。

(完)

posted @ 2012-12-30 23:16  风中散发  阅读(...)  评论(...编辑  收藏