微信服务号的消息处理

新产品会和微信公众号有交互,所以就来尝尝鲜,做一做微信公众号的各种东西.

首先:注册,认证,bla bla bla,设置一堆东西

在获得了开发权限之后,就可以仔细阅读开发文档了.

和微信的交互有两种:

  1. 服务器给微信发送消息
  2. 微信给服务器发送消息

说说他们的区别.

服务器给微信发消息,很方便,发表单格式的就行了,微信回复的是json格式的

微信服务器主动给服务器发消息,就很恶心了.

  1. 如果在配置页面设置了消息模式是加密的,那么收到了微信的消息之后需要先对包进行解密,才能得知微信发送的消息的确切内容.
  2. 微信的每次请求,都需要按照和它一样的变态格式回复.
  3. 还得验证验证消息到底是不是微信发的~

先来看看微信给服务器发的是什么样子的东西

<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>

哦,这个是没加密的,加密的更难看…

应该用正则来提取内容吧,我把他们都写了出来,方便方便

REGEX_TOUSERNAME = r'\<ToUserName\>\<\!\[CDATA\[(.*)\]\]\>\<\/ToUserName\>'
REGEX_FROMUSERNAME = r'\<FromUserName\>\<\!\[CDATA\[(.*)\]\]\>\<\/FromUserName\>'
REGEX_MSGTYPE = r'\<MsgType\>\<\!\[CDATA\[(.*)\]\]\>\<\/MsgType\>'
REGEX_EVENT = r'\<Event\>\<\!\[CDATA\[(.*)\]\]\>\<\/Event\>'
REGEX_EVENT_KEY = r'\<EventKey\>\<\!\[CDATA\[(.*)\]\]\>\<\/EventKey\>'
REGEX_SCANTYPE = r'\<ScanType\>\<\!\[CDATA\[(.*)\]\]\>\<\/ScanType\>'
REGEX_SCANRESULT = r'\<ScanResult\>\<\!\[CDATA\[(.*)\]\]\>\<\/ScanResult\>'
REGEX_CREATETIME = r'\<CreateTime\>(.*)\<\/CreateTime\>'
REGEX_CONTENT = r'\<Content\>\<\!\[CDATA\[(.*)\]\]\>\<\/Content\>'

还傻乎乎的搞了个类来解析这坨东西

class wechat_xml_object(object):
    def __init__(self, xml):
        self.origin = str(xml)

    @property
    def toUserName(self):
        return self.returnValueForKey(REGEX_TOUSERNAME)

    @property
    def fromUserName(self):
        return self.returnValueForKey(REGEX_FROMUSERNAME)

    @property
    def msgType(self):
        return self.returnValueForKey(REGEX_MSGTYPE)

    @property
    def event(self):
        return self.returnValueForKey(REGEX_EVENT)

    @property
    def eventKey(self):
        return self.returnValueForKey(REGEX_EVENT_KEY)

    @property
    def scanType(self):
        return self.returnValueForKey(REGEX_SCANTYPE)

    @property
    def scanResult(self):
        return self.returnValueForKey(REGEX_SCANRESULT)

    @property
    def createTime(self):
        return self.returnValueForKey(REGEX_CREATETIME)

    @property
    def content(self):
        return self.returnValueForKey(REGEX_CONTENT)

    def returnValueForKey(self, regex):
        match = re.search(regex,self.origin)
        if match:
            return match.group(1)
        else:
            return None

虽然我知道有kissXML这种神器,但是我得装……

上面是把明文的XML解包出来,现在我们把想回复的数据给封装起来

class wechat_xml_builder(object):
    def __init__(self, data_type):
        self.type = data_type
        self.content = ''
        self.contains = []

    def addObject(self, key, value, data_mark):
        if key in self.contains:
            return False
        if data_mark:
            self.content += '<{0}><![CDATA[{1}]]></{2}>'.format(key, value, key)
        else:
            self.content += '<{0}>{1}</{2}>'.format(key, value, key)
        self.contains.append(key)
        return True

    def add_default_from(self, dictionary):
        fromUser = dictionary['toUser']
        openid = dictionary['openid']
        createTime = dictionary['createTime']
        self.addObject('ToUserName', openid, True)
        self.addObject('FromUserName', fromUser, True)
        self.addObject('CreateTime', createTime, False)

    def exportString(self):
        return '<xml>' + self.content + '</xml>'

我感觉这个类用起来还是蛮简单的.

至于说加密和解密,微信还是很良心的提供了一个库,可以直接操作.

下次再整理一下微信开发中其他的坑儿吧