利用SAE搭建微信公众平台(二)微信的验证和自动回复

上篇文章讲了如何在SAE搭建Hello World,那么这篇文章主要写如何实现微信的验证和自动回复。

首先修改SAE中的index.wsgi文件如下:

[python]
# coding: UTF-8
import os

import sae
import web

from weixinInterface import WeixinInterface

urls = (
‘/’, ‘Hello’,
‘/weixin’,’WeixinInterface’
)

app_root = os.path.dirname(__file__)
templates_root = os.path.join(app_root, ‘templates’)
render = web.template.render(templates_root)

class Hello:
def GET(self):
#print "你好"
return render.hello("你好")

app = web.application(urls, globals()).wsgifunc()

application = sae.create_wsgi_app(app)
[/python]

即创建一个weixinInterface类来处理微信的请求。
在目录下创建weixinInterface文件,定义WeixinInterface类。

一、实现微信验证。

回顾微信开发者的验证方式(一下摘自微信官方文档):

填写信息

公众平台用户提交信息后,微信服务器将发送GET请求到填写的URL上,并且带上四个参数:

参数 描述
signature 微信加密签名
timestamp 时间戳
nonce 随机数
echostr 随机字符串

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。

signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

加密/校验流程:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

那么首先要解决的就是get方法的问题。在WeixinInterface模块中添加代码如下:

[python]
#coding:UTF-8
import hashlib
import web
class WeixinInterface:

def GET(self):
#获取输入参数
data=web.input()

signature=data.signature
timestamp=data.timestamp
nonce=data.nonce
echostr=data.echostr
#自己的token
token="yourtoken"
#字典序排序
list=[token,timestamp,nonce]
list.sort()
#sha1加密算法
sha1=hashlib.sha1()
map(sha1.update,list)
hashcode=sha1.hexdigest()
#如果是来自微信的请求,则回复echostr
if hashcode == signature:
#print "true"
return echostr
[/python]

现在,放回微信公众平台的注册界面,填上你的验证地址即:http://yourdomain.sinaapp.com/weixin,token填自己的token,要和上面程序中一致。点击提交,如果没有意外现在就应该验证成功了。

二、实现简单的文本回复

现在阅读微信公众平台的文档,先只注意接收文本信息和回复文本信息的格式:

消息推送

当普通微信用户向公众账号发消息时,微信服务器将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>
<MsgId>1234567890123456</MsgId>
</xml>
[/xml]


参数 描述
ToUserName 开发者微信号
FromUserName 发送方帐号(一个OpenID)
CreateTime 消息创建时间 (整型)
MsgType text
Content 文本消息内容
MsgId 消息id,64位整型

消息回复

对于每一个POST请求,开发者在响应包中返回特定xml结构,对该消息进行响应(现支持回复文本、图文、语音、视频、音乐和对收到的消息进行星标操作)。 微信服务器在五秒内收不到响应会断掉连接。 回复xml结构如下:

回复文本消息

[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>
[/xml]

参数 描述
ToUserName 接收方帐号(收到的OpenID)
FromUserName 开发者微信号
CreateTime 消息创建时间
MsgType text
Content 回复的消息内容,长度不超过2048字节
FuncFlag 位0x0001被标志时,星标刚收到的消息。

那么显然的是,我们需要解析xml文件。SAE预装了lxml库,能够方便的解析xml。首先切换到config.yaml,添加代码,效果如下:

[code]

name: tedxfactory798
version: 1
libraries:
– name: webpy
version: "0.36"
– name: lxml
version: "2.3.4"
[/code]

下面切换回weixinInterface文件,代码如下:

[python]
#coding:UTF-8
import hashlib
import web
import lxml
import time
import os
from lxml import etree
class WeixinInterface:

def __init__(self):
self.app_root = os.path.dirname(__file__)
self.templates_root = os.path.join(self.app_root, ‘templates’)
self.render = web.template.render(self.templates_root)

def GET(self):
#获取输入参数
data=web.input()

signature=data.signature
timestamp=data.timestamp
nonce=data.nonce
echostr=data.echostr
#自己的token
token="yourtoken"
#字典序排序
list=[token,timestamp,nonce]
list.sort()
#sha1加密算法
sha1=hashlib.sha1()
map(sha1.update,list)
hashcode=sha1.hexdigest()
#如果是来自微信的请求,则回复echostr
if hashcode == signature:
#print "true"
return echostr

def POST(self):
#从获取的xml构造xml dom树
str_xml=web.data()
xml=etree.fromstring(str_xml)
#提取信息
content=xml.find("Content").text
msgType=xml.find("MsgType").text
fromUser=xml.find("FromUserName").text
toUser=xml.find("ToUserName").text
#模板渲染
return self.render.reply_text(fromUser,toUser,int(time.time()),u"大家好我现在还只会卖萌,你刚才说的是:"+content)
[/python]

那么我们还需要建立一个模板,在template目录下,reply_text.xml:

[xml]
$def with (toUser,fromUser,createTime,content,funcFlag=0)
<xml>
<ToUserName><![CDATA[$toUser]]></ToUserName>
<FromUserName><![CDATA[$fromUser]]></FromUserName>
<CreateTime>$createTime</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[$content]]></Content>
<FuncFlag>$funcFlag</FuncFlag>
</xml>
[/xml]

保存全部文件,注意一下toUser和fromUser的顺序,和接受的时候正好相反。

如果没有错的话~在微信上加上自己的公众账号测试吧!

上一篇文章:利用SAE搭建微信公众平台(一)

下一篇文章:利用SAE搭建微信公众平台(三)

24 评论

    1. 可以看一下sae的日志中的debug信息。这篇文章貌似错误有点多,稍微看一下评论。以及推荐你看这个系列之三,用了一个新的框架,应该比较好用。

  1. Traceback (most recent call last): File “/data1/www/htdocs/303/lylab/1/index.wsgi”, line 7, in from weixinInterface import WeixinInterfaceImportError: No module named weixinInterface怎么回事,找不到,我已经新建weixinIterface.py了

  2. 博主你好,在搭建微信公众平台开始,按照你的示例代码写入,微信那边token验证没有响应,我检查了好久都没找出原因,能否解答一下?

  3. 如果不出来你们可以试试我这个:第一个:reply_text.xml中的“”改成“text”;第二个:config.yaml下面的两个“version”都没对齐,第三个:可以在weixinInterface.py中加入 “import urllib2,json”

发表评论

电子邮件地址不会被公开。 必填项已用*标注