html
以前写了一篇搭建sae的python平台,经过微信公众平台验证的博文。如今就是要承上启下,开始开发的第一步。也许你会说开发的第一步就是写代码。那我会对你表示鄙视,尽管南苑随笔是个很简单的应用,可是多少也还须要设计一下。肯定一下需求,为了未来可以吸引到粉丝来关注个人公众号,我必需要定位好个人app,而后提供优秀的内容,并肯定它的运营模式,才能进一步地提高咱们的应用水准。python
首先,这个app是要用python写的,那么就必定要优雅一点,pythonic一点。对于我本身来讲,我要使得这个app至少可以知足我阅读若干与南苑相关的文章的要求才行。故而须要对南苑随笔进行需求分析:linux
定位: 为南苑或者外校同窗提供咱们在南苑生活和学习的文章。文体不限,内容形式包括{图片,语音,文字},推送给用户,这正是微信可以提供给个人。web
约定: 容许投稿,可是投稿必须经过管理员的审核。其实很大程度上,咱们是为了向粉丝们推介 @bibo-果冻 和 @daoluan-郑思愿 合做的那本《南苑随笔——IT小小鸟外传》。数据库
内容: 校园生活,学习,感情,分享,趣味,摄影,文学做品,简单社交 ,歌曲等等。django
服务: 提供每1天/2天按期推送文章或语音。同时相应用户发来的请求,对用户请求进行分析后返回所要求的内容。编程
性能: 要求服务器在5秒内返回用户的请求内容,在网络差的时候,这个就难说了。可以同时处理至少20位粉丝的请求(其实到底有没有这么多粉丝发来请求,我内心仍是没有数啊)。ubuntu
此次,我吸收了上次的经验教训,要先完成逻辑和数据的设计,最后才去设计咱们的交互界面(包括交互方式和菜单)。数据先行,那么一切就从构建起数据库开始。参照wordpress的博客数据库,就能够设计出基本的数据库框架。这部分就交给 @daoluan-思愿 来搞定,我相信他会完成的至关出色。浏览器
本系统须要一个博客系统,和一个微信服务app,博客系统做为web端,用浏览器可访问的。而微信app则负责推送到用户的微信账号聊天界面。故而咱们的数据库设计就很清晰了,须要:服务器
user表——用户
post表——文章
blog配置——博客的设置
category表——分类
———————————次要———————————
url表——友情连接
guest_book表——留言簿
而我须要用到的仅仅是博客系统数据库的一个子集——post表和guest_book表(也许会用到category表)。故而开发微信app则只须要自行建立两个表进行实验便可。
暂且不把设计逻辑排到日程上来,咱们来尝试一下在第三方服务器和微信服务器,以及客户端进行通讯。假如用户发送来一个请求,因为已经绑定了URL,且开启了开发模式,那么就微信服务器就会转发这个请求到咱们的服务器,咱们的服务器要解析这个请求,而后返回所请求的内容。
咱们须要一个类来处理get请求,以及定时向微信服务器传送群发的文章。
该类 weixin_scnuwriter设计以下:
handle_request(request) # 处理请求
parse_request_xml(xml) # 解析请求
response_msg(request) # 响应请求(关键逻辑部分)
pack_text_xml(post_msg, response_msg) # 打包响应的文本内容,须要参考微信API,供response_msg调用
# 另外在数据库方面要可以读取,须要django于数据库打交道,不过咱们暂时不实现,只是作一个简单的测试。
下面是handle_request代码:
1
2
3
4
5
6
7
8
9
|
def
handle_request(request):
if
request.method
=
=
'GET'
:
response
=
HttpResponse(check_signature(request),content_type
=
"text/plain"
)
# 若是是GET请求,那么核对签名
return
response
elif
request.method
=
=
'POST'
:
response
=
HttpResponse(response_msg(request),content_type
=
"application/xml"
)
# 若是是POST请求,那么响应消息
return
response
else
:
return
None
|
咱们以前写认证的时候,都是直接将url导向到check_signature直接进行响应处理,可是这里咱们对请求的类型进行区分,由于验证的时候发送的是GET请求,而对咱们本身的服务器推送消息的时候,它是使用POST请求的,由于POST方法能够向服务器发送大量的数据(表单提交,文件上传等),在这里是xml结构。记得要在urls里面配置一个到handle_request的映射,个人是:“ url(r'^$', handle_request), ”。逗号是不能丢的。
handle_request须要调用check_signature,以前咱们用了return HttpResponse(echoStr)来验证,可是咱们把HttpResponse的封装放到了handle_request中,那么咱们就只需在check_signature中返回echoStr就好了,固然,验证一次就好了,如今已经进入开发阶段,这函数将用不到。其实应该在一开始,咱们就应该像如今同样写。check_signature以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 检测签名,只对get有效
def
check_signature(request):
global
TOKEN
signature
=
request.GET.get(
"signature"
,
None
)
timestamp
=
request.GET.get(
"timestamp"
,
None
)
nonce
=
request.GET.get(
"nonce"
,
None
)
echoStr
=
request.GET.get(
"echostr"
,
None
)
token
=
TOKEN
tmpList
=
[token,timestamp,nonce]
tmpList.sort()
tmpstr
=
"%s%s%s"
%
tuple
(tmpList)
tmpstr
=
hashlib.sha1(tmpstr).hexdigest()
if
tmpstr
=
=
signature:
return
echoStr
else
:
return
None
|
很明显15行变了。浏览器和服务器之间,并非简单的传递数据,还有解析包的过程,服务器返回一个http类型的文档,浏览器要进行协议解析,读取头部等东西,进而解析出整个文档。这就是为何须要在返回的时候包装成HttpResponse,不然浏览器读不懂,django就报错说:返回的不是一个httpresponse类型的对象。我曾经参考《linux C 编程指南》写过一个简单的服务器程序,服务器程序,发送了固定的头部,而后对各类不一样类型的返回打印不一样的文档,例如404,503等等,而对于正常状况,则读取一个html文件予以返回。协议与就是相互商量好的约定,故而协议通常都约定了要以什么开头,或者按照协议里写的东西来解析。
下面是parse_request_xml函数,用来解析请求,该请求来自微信服务器,包含了一个xml结构,使用的是POST方法,待会咱们就用个工具来测试一下怎么模拟POST请求,而不使用微信发送(微信发送须要通过微信服务器,并且咱们不知道错在哪里)。
1
2
3
4
5
6
7
|
# 解析请求,拆解到一个字典里
def
parse_request_xml(rootElem):
msg
=
{}
if
rootElem.tag
=
=
'xml'
:
for
child
in
rootElem:
msg[child.tag]
=
smart_str(child.text)
# 得到内容
return
msg
|
很明显,对于一个xml结构(实际上是一个字符串),进行解析,就须要用到它的tag,来区分究竟是什么内容,以及获取对应tag的内容,放到python咱们程序中的一个字典结构里。
下面是response_msg函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
response_msg(request):
# 从request中获取输入文本
rawStr
=
smart_str(request.raw_post_data)
# 将文本进行解析,获得请求的数据
msg
=
parse_request_xml(ET.fromstring(rawStr))
# 根据请求消息来处理内容返回
query_str
=
msg.get(
"Content"
)
# query_str = "hello"
response_msg
=
""
# 使用简单的处理逻辑,有待扩展
if
query_str
=
=
"hello"
:
response_msg
=
"hello to you too"
else
:
response_msg
=
"how are you, unkown"
# 返回消息
# 包括post_msg,和对应的 response_msg
return
pack_text_xml(msg, response_msg);
|
消息回应,这里的逻辑很简单,对于hello,就返回一个hello to you too, 其余则返回 how are you , unkown。未来用户若是发来“第一篇”等请求,咱们将返回完整的图文消息。这部分是有待开发的。
上面的回应函数用到了打包返回消息成xml这样的功能,pack_text_xml函数以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 打包消息xml,做为返回
def
pack_text_xml(post_msg,response_msg):
# f = post_msg['FromUserName']
# t = post_msg['FromUserName']
text_tpl
=
'''<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>'''
text_tpl
=
text_tpl
%
(post_msg[
'FromUserName'
],post_msg[
'ToUserName'
],
str
(
int
(time.time())),
'text'
,response_msg)
# 调换发送者和接收者,而后填入须要返回的信息到xml中
return
text_tpl
|
能够看到text_tpl其实就是微信API内容的一个——返回text,就是聊天记录同样的文本。对于其它内容,有其余内容的模板,能够到微信公众账号API察看。这里须要说明的是xml结构里面要填参数的地方,都有一个占位符号%s,表示的是一个字符串。而后对于模板,填如咱们的参数。如第12行所示。
好了,咱们能够开始测试了。我google了一下,有人说使用firefox的poster插件,很是好用。因而我就在firefox下装了一个,来模拟各类各样不一样的http请求。首先,要有一个firefox浏览器,ubuntu如今是自带了,无需安装,若是没有能够去官网下载。而后安装poster,点这里,找到了poster插件,在firefox安装就好了。好了,咱们能够模拟微信服务器发送咱们的消息转发了,以下:
使用时,填入post请求时发送的xml,还有你的服务器的url,例如个人是: http://scnuwriter.sinaapp.com 而后点post,就能够看到下面的画面:
能够看到咱们的服务器返回了 hello to you too,这是和咱们的程序相符合的。可是可能你获得的是一个403fobidden。我google了一下,stack overflow里面说,那多是由于咱们没有启用跨站请求,以防止***,具体参考python的csrf文档。后来我修改了settings.py文件里面的middleware配置:
1
2
3
4
5
6
7
8
9
10
11
12
|
MIDDLEWARE_CLASSES
=
(
'django.middleware.common.CommonMiddleware'
,
'django.contrib.sessions.middleware.SessionMiddleware'
,
'django.middleware.csrf.CsrfViewMiddleware'
,
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
# for post:
#'django.middleware.csrf.CsrfResponseMiddleware',
# Uncomment the next line for simple clickjacking protection:
#'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
|
很奇怪,我去掉第8行CsrfResponseMiddleware以后,服务器就出错了。故而我注释了它,而后在views.py的最前面的函数前面加上一个:@csrf_exempt 。结果就好了,获得上面截图的内容。要深刻了解这是为何,还须要了解web的更多信息,还有django的官方文档,bibo也要好好充电了,知其然,不知其因此然,不可谓为知也。
好吧,用svn上传你的成果到服务器上吧,用手机来测试。通常用post获得了正确回应都不会有错的。bibo在本身的手机微信上面发送了一个"hello",真的收到了一个"hello to you too"。第一次尝试微信编程,竟然成功了!yeah。并且还学会了一个工具poster。
by bibodeng 2013-04-19 士别三日,当另眼相看
scnuwriter示例下载连接:http://vdisk.weibo.com/s/y9wJz 主要看views.py