.. include:: ../LINKS.rst 再次重构 ============================ 追加新的有流程的指令前,要先解决一个问题: ``怎么在本地调试?!`` - 之前, 是通过 ``dev_server.py`` 提供的本地测试服务跑起来, - 然后使用 `cURL`_ 在命令行上模拟微信发送来的消息 `XML`_ 可是! 那是 `XML`_ 大堆大堆的标签,每次变动 ``指令`` 要在终端移动光标进行合理的修订,慢! 又容易出问题! 所以! 首先要有个命令行工具 --------------------------------- 解决快速向本地测试服务发送吻合格式的测试请求! 进一步的说,就是可以根据简单的参数指定来组合出以下类似的命令,再执行:: curl -d '[XML请求字串]' http://localhost:8080/api/echo 而 ``[XML请求字串]`` 就是文档早已约定了的:: 1348831860 1234567890123456 每次本地测试时,嘦对 ```` 进行替换而已 所以 ``CLI.py`` 就是: .. code-block:: python :linenos: :emphasize-lines: 2-3,6,13-14,18 # -*- coding: utf-8 -*- import sys from time import time from subprocess import Popen from xsettings import XCFG if __name__ == "__main__": if 2 != len(sys.argv): print """ Usage:: $ python CLI.py [指令] """ else: TPL_TEXT=''' %(tStamp)s ''' toUser = XCFG.AS_SRV fromUser = XCFG.AS_USR tStamp = int(time()) content = sys.argv[1] xml = TPL_TEXT % locals() cmd = "curl -d '%s' http://localhost:8080/api/echo"% xml print cmd #Popen(cmd, shell=True, close_fds=True) 是的,就这样,就解决了一个现实的问题:: $ python chaos_CLI.py Usage:: $ python CLI.py [指令] $ python chaos_CLI.py h $ python chaos_CLI.py s ... 使用时,就将要发送到服务端的复杂的 `XML`_ 消息模拟,变成了只要变更指令本身就好! 唯一的技巧 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``from xsettings import XCFG`` 意思,就是关键的涉及安全的参数,不进入开源仓库, 使用专门的配置文件进行管理, 形式上完全类似前述在使用的 ``config.py`` 当然的, 使用 `GitHub`_ 时,要对应配置 ``.gitignore`` :: .ropeproject *.dump *.pyc *.db *.log .svn .DS_Store *.wsgic logs xsettings.py 追加 ``xsettings.py`` 改造指令响应函式 --------------------------------- 再来看一下 `web/mana4api.py` 关键部分已经扩展为: .. code-block:: python :linenos: :emphasize-lines: 1-2,17,18,20,34-39 import sae.kvdb KV = sae.kvdb.KVClient() #... @APP.post('/echo') @APP.post('/echo/') def wechat_post(): xml = etree.XML(request.forms.keys()[0]) fromUser = xml.findtext("ToUserName") toUser = xml.findtext("FromUserName") __MsgType = xml.findtext("MsgType") __Content = xml.findtext("Content") tStamp = TSTAMP() if "text" == __MsgType: if "h" == __Content: content = "是也乎" return CFG.TPL_TEXT% locals() elif "i" == __Content: uid = hashlib.sha1(toUser).hexdigest() print uid usr = KV.get(uid) if None == usr: # 首次应答,没有建立档案 pass else: # 已经有档案 if "em" in usr.keys(): # 曾经记录过邮箱 content = "你的邮箱: %s"% usr['em'] else: # 未记录过 content = "请输入你的邮箱如\nem:foo@bar.com" print CFG.TPL_TEXT% locals() return CFG.TPL_TEXT% locals() elif "em" in __Content.split(":"): uid = hashlib.sha1(toUser).hexdigest() usr = KV.get(uid) print __Content[3:] usr['em'] = __Content[3:] KV.replace(uid, usr) content = "你的邮箱: %s"% usr['em'] print CFG.TPL_TEXT% locals() return CFG.TPL_TEXT% locals() return None 先来尝试将设想中的文章查阅逻辑加到这个越来越长的 ``if elif else`` 判定树中: .. code-block:: python :linenos: :emphasize-lines: 1-2,17,18,20,34-39 #... @APP.post('/echo') @APP.post('/echo/') def wechat_post(): xml = etree.XML(request.forms.keys()[0]) fromUser = xml.findtext("ToUserName") toUser = xml.findtext("FromUserName") __MsgType = xml.findtext("MsgType") __Content = xml.findtext("Content") tStamp = TSTAMP() if "text" == __MsgType: if "h" == __Content: content = "是也乎" return CFG.TPL_TEXT% locals() elif "s" == __Content: #进入查询流程 pass elif "dd" == __Content: # 进入查询 dd ~ D码点评分类列表 pass elif "某个文章编号" == __Content: # 进入输出指定分类文章中具体文章图文链接 pass elif "i" == __Content: .. warning:: (\\o/)||| - 停!!!! if else 无能为力! --------------------------------- .. _fig_3_2: .. figure:: ../_static/figs/chaos3-2-gdg_seek_words.png 插图 3-2 如果包含一个支持随时退出流程的 ``*`` 指令 其实整个查阅公众号过往文章的业务,和一般的电话银行业务是没有什么不同的, 所以,也可以自然的追加一个 ``*`` 指令,退回上级菜单,或是退出查阅流程. 一般的条件判定结构: ``if elif else`` 对此是完全无力的: - 因为公众号的应答,完全同web 网站的反馈 - 每次不同的成员输入指令,对于服务端而言都是全新的,独立的一次请求 - 服务端虽然可以识别用户,但是,用户上次输入了什么指令,以及指令序列的上下文,是无法通过简单的条件判定来得出的 - 因为成员是人,是人就会出错, 而且在移动端,什么情况都会发生,要想确保流程稳定可用,就需要预先对所有情况都加以判定! 想想都是个麻烦的事儿! **BazingA** 那肿么办呢....