Django之微信公众号踩坑之旅

一、微信公众号的准备:

  1. 注册
    访问地址:https://mp.weixin.qq.com/
    按照提示注册即可

  2. 配置
    需要准备好自己的服务器地址,可以使用腾讯云阿里云京东云等等皆可,没有域名用IP也可以。
    在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。
    详细配置文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

  3. 连接
    服务器配置提交后,微信服务器发送GET请求到填写的服务器地址URL上,GET请求携带参数包括signature、timestamp、nonce、echostr,服务端程序通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容给微信服务器确认后接入生效。加密/校验流程如下,下文中有代码具体实现:
    1)将token、timestamp、nonce三个参数进行字典序排序
    2)将三个参数字符串拼接成一个字符串进行sha1加密
    3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

二、基于Django开发微信公众号后台的步骤:
1.准备工作
新建 django project,项目名暂定 my_wechat

django-admin.py startproject  my_wechat

新建 app
进入项目目录下,cd project_wechat 然后执行下面的命令

python manage.py startapp wechat
或
django-admin.py startapp wechat

1
修改settings.py加入刚才创建的wechat应用

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'wechat',
)

修改项目同名app内的urls.py,添加新的app wechat的路由解析跳转

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^wechat/', wechat ,name="wechat")),
   ]

3.编写wechat应用的views.py
get方法做校验,post方法传xml数据,解析和拼凑xml数据实现自动回复功能

import logging
import hashlib
import time
import xml.etree.ElementTree as ET

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse



# django默认开启csrf防护,这里使用@csrf_exempt去掉防护
@csrf_exempt
def weixin_main(request):
    if request.method == "GET":
        # 接收微信服务器get请求发过来的参数
        try:
            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 = 'hello'
            token = "hello"
            # 把参数放到list中排序后合成一个字符串,
            # 再用sha1加密得到新的字符串与微信发来的signature对比,
            # 如果相同就返回echostr给服务器,校验通过
            list = [token, timestamp, nonce]
            list.sort()
            list = ''.join(list)
            hashcode = hashlib.sha1(list.encode("utf-8")).hexdigest()
            # 官方文档中的hashlib部分出错
            # list = [token, timestamp, nonce]
            # list.sort()
            # sha1 = hashlib.sha1()
            # map(sha1.update, list)
            # hashcode = sha1.hexdigest()
            if hashcode == signature:
                logging.error(hashcode)
                return HttpResponse(echostr)
            else:
                return HttpResponse("field")
        except Exception as e:
            logging.error('%s' % e)
            return HttpResponse(echostr)
    else:
        othercontent = autoreply(request)
        return HttpResponse(othercontent)



#微信服务器推送消息是xml的,根据利用ElementTree来解析出的不同xml内容返回不同的回复信息,
# 就实现了基本的自动回复功能了,也可以按照需求用其他的XML解析方法
def autoreply(request):
    try:
        webData = request.body
        xmlData = ET.fromstring(webData)

        msg_type = xmlData.find('MsgType').text
        ToUserName = xmlData.find('ToUserName').text
        FromUserName = xmlData.find('FromUserName').text
        CreateTime = xmlData.find('CreateTime').text
        MsgType = xmlData.find('MsgType').text
        MsgId = xmlData.find('MsgId').text

        toUser = FromUserName
        fromUser = ToUserName


        if msg_type == 'text':
            content = "Hello World!"
            replyMsg = TextMsg(toUser, fromUser, content)
            print("成功了!!!!!!!!!!!!!!!!!!!")
            print(replyMsg)
            return replyMsg.send()

    except Exception as Argment:
        return Argment


class Msg(object):
    def __init__(self, xmlData):
        self.ToUserName = xmlData.find('ToUserName').text
        self.FromUserName = xmlData.find('FromUserName').text
        self.CreateTime = xmlData.find('CreateTime').text
        self.MsgType = xmlData.find('MsgType').text
        self.MsgId = xmlData.find('MsgId').text


class TextMsg(Msg):
    def __init__(self, toUserName, fromUserName, content):
        self.__dict = dict()
        self.__dict['ToUserName'] = toUserName
        self.__dict['FromUserName'] = fromUserName
        self.__dict['CreateTime'] = int(time.time())
        self.__dict['Content'] = content

    def send(self):
        XmlForm = """
        <xml>
        <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
        <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
        <CreateTime>{CreateTime}</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[{Content}]]></Content>
        </xml>
        """
        return XmlForm.format(**self.__dict)

根据官方提供的文档开发时遇到token一直验证错的问题,经过分析后发现官方提供的hashlib加密的例子有问题,在期间会出现一下问题:

Unicode-objects must be encoded before hashing

这是因为

# hashlib.hashlib(data)函数中,data参数的类型应该是bytes
# hash前必须把数据转换成bytes类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值