django+python微信开发之三-消息处理类

###消息处理类wechatUtil.py
上一篇封装了三种消息类型,wechatMessage.py,wechatEvent.py和wechatReply.py。微信是以xml格式处理信息的,所以要处理xml得到相应的信息。这里用lxml库来处理,先贴上代码再解释:

# -*- coding:utf-8 -*-
"""
# Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today)
# Created Time : Wed Feb 18 18:18:10 2015

# File Name: wechatUtil.py
# Description:

# :copyright: (c) 2015 by Pegasus Wang.
# :license: MIT, see LICENSE for more details.
"""

import hashlib
from lxml import etree


def checkSignature(request):
    """check signature.

    :param request: get method
    :return: if success return True else False
    """
    signature = request.GET.get(u'signature', None)
    timestamp = request.GET.get(u'timestamp', None)
    nonce = request.GET.get(u'nonce', None)
    token = u'pegasuswang'    # your wechat token

    tmplist = [token, timestamp, nonce]
    tmplist.sort()
    tmpstr = '%s%s%s' % tuple(tmplist)
    tmpstr = hashlib.sha1(tmpstr).hexdigest()

    if tmpstr == signature:
        return True
    else:
        return False


class MessageUtil(object):
    """MessageUtil has some methods to process message."""
    # request message types
    REQ_MESSAGE_TYPE_TEXT = u'text'
    REQ_MESSAGE_TYPE_IMAGE = u'image'
    REQ_MESSAGE_TYPE_VOICE = u'voice'
    REQ_MESSAGE_TYPE_VIDEO = u'video'
    REQ_MESSAGE_TYPE_LOCATION = u'location'
    REQ_MESSAGE_TYPE_LINK = u'link'
    REQ_MESSAGE_TYPE_EVENT = u'event'

    # event types
    EVENT_TYPE_SUBSCRIBE = u'subscribe'
    EVENT_TYPE_UNSUBSCRIBE = u'unsubscribe'
    EVENT_TYPE_SCAN = u'scan'
    EVENT_TYPE_LOCATION = u'LOCATION'
    EVENT_TYPE_CLICK = u'CLICK'

    # reply message types
    RESP_MESSAGE_TYPE_TEXT = u'text'
    RESP_MESSAGE_TYPE_IMAGE = u'image'
    RESP_MESSAGE_TYPE_VOICE = u'voice'
    RESP_MESSAGE_TYPE_VIDEO = u'video'
    RESP_MESSAGE_TYPE_MUSIC = u'music'
    RESP_MESSAGE_TYPE_NEWS = u'news'

    # message types
    MESSAGETYPE = [u'Image', u'Voice', u'Video', u'Music', u'Articles']

    @staticmethod
    def parseXml(request):
        """parse request post xml message.

        :param request: post request
        :return: dict of xml message
        """
        raw_xml = request.body.decode(u'UTF-8')
        xmlstr = etree.fromstring(raw_xml)
        dict_xml = {}
        for child in xmlstr:
            dict_xml[child.tag] = child.text.encode(u'UTF-8')    # note
        return dict_xml



    @staticmethod
    def class2xml(obj):
        """convert reply message class to xml.

        :param obj: reply message class' object
        :return: xml of the object
        """
        root = etree.Element(u'xml')
        for key, value in vars(obj).items():
            if key in MessageUtil.MESSAGETYPE:
                tmproot = etree.SubElement(root, key)
                if key == u'Articles':    # solve Article, it's special
                    for eachArticle in value:
                        etree.SubElement(tmproot, u'item')
                        for tmpkey, tmpvalue in vars(eachArticle).items():
                            tmpkey_ele = etree.SubElement(tmproot, tmpkey)
                            tmpkey_ele.text = etree.CDATA(unicode(tmpvalue))
                else:
                    for tmpkey, tmpvalue in vars(obj.__getattribute__(key)).items():
                        tmpkey_ele = etree.SubElement(tmproot, tmpkey)
                    if u'time' in tmpkey.lower() or u'count' in tmpkey.lower():
                        tmpkey_ele.text = unicode(tmpvalue)
                    else:    # CDATA tag for str
                        tmpkey_ele.text = etree.CDATA(unicode(tmpvalue))
            else:
                if u'time' in key.lower() or u'count' in key.lower():
                    etree.SubElement(root, key).text = unicode(value)
                else:
                    etree.SubElement(root, key).text = etree.CDATA(unicode(value))

        return etree.tostring(root, pretty_print=True, xml_declaration=False, encoding=u'utf-8')

###checkSignature方法
参考:验证消息真实性http://mp.weixin.qq.com/wiki/4/2ccadaef44fe1e4b0322355c2312bfa8.html
开发文档给出的是php的代码,改写成python也很简单。

加密/校验流程如下:

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

###消息处理类MessageUtil

  • 类型定义:定义了一些列变量标识消息类型
  • parseXml方法:用来解析微信公众账号post过来的xml信息,得到发送人、发送时间、消息内容等信息,返回一个字典。使用lxml库。
  • class2xml方法:没有找到相应的库把reply消息对应的类转换成xml格式,这个是我自己写的一个方法,用来把reply类转换成xml返回给微信公众账号。测试信息如下:
    测试TextReply