使用Django進行微信公眾號開發
一、微信公眾號的準備:
1. 註冊
訪問地址:https://mp.weixin.qq.com/
按照提示註冊即可
注意:本文樣例使用個人公眾號,由於個人公眾號沒有介面許可權,自定義選單無法進行開發,同學們不要註冊錯!
2. 配置
需要準備好自己的伺服器地址,可以使用騰訊雲阿里雲京東雲等等皆可,沒有域名用IP也可以。
在公眾平臺官網的開發-基本設定頁面,勾選協議成為開發者,點選“修改配置”按鈕,填寫伺服器地址(URL)、Token和EncodingAESKey,其中URL是開發者用來接收微信訊息和事件的介面URL。Token可由開發者可以任意填寫,用作生成簽名(該Token會和介面URL中包含的Token進行比對,從而驗證安全性)。EncodingAESKey由開發者手動填寫或隨機生成,將用作訊息體加解密金鑰。
詳細配置文件:
3. 連線
伺服器配置提交後,微信伺服器傳送GET請求到填寫的伺服器地址URL上,GET請求攜帶引數包括signature、timestamp、nonce、echostr,服務端程式通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信伺服器,請原樣返回echostr引數內容給微信伺服器確認後接入生效。加密/校驗流程如下,下文中有程式碼具體實現:
1)將token、timestamp、nonce三個引數進行字典序排序
2)將三個引數字串拼接成一個字串進行sha1加密
3)開發者獲得加密後的字串可與signature對比,標識該請求來源於微信
二、基於Django開發微信公眾號後臺的步驟:
1.準備工作
- 新建 django project,專案名暫定devnav
django-admin.py startproject devnav
- 新建 app
進入專案目錄下,cd project_wechat 然後執行下面的命令
python manage.py startapp wechat
或
django-admin.py startapp wechat
- 修改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'^wx/', include('wechat.urls',namespace="wechat")),
]
2.編寫wechat應用的urls.py
修改app wechat內的urls.py,新增針對檢視函式的解析,預設訪問指向檢視函式的weixin_main方法,若有其他方法可參考註釋中的startmymenu方法來編寫
app_name = 'wechat'
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$', views.weixin_main, name='weixin_main'),
#url(r'^startmymenu$', views.startmymenu, name='startmymenu'),
]
3.編寫wechat應用的views.py
get方法做校驗,post方法傳xml資料,解析和拼湊xml資料實現自動回覆功能
# Create your views here.
# -*- coding: utf-8 -*-
import hashlib
import json
from django.utils.encoding import smart_str
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請求發過來的引數
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 = '寫你的token在這裡'
#把引數放到list中排序後合成一個字串,再用sha1加密得到新的字串與微信發來的signature對比,如果相同就返回echostr給伺服器,校驗通過
hashlist = [token, timestamp, nonce]
hashlist.sort()
hashstr = ''.join([s for s in hashlist])
hashstr = hashlib.sha1(hashstr).hexdigest()
if hashstr == signature:
return HttpResponse(echostr)
else:
return HttpResponse("field")
else:
othercontent = autoreply(request)
return HttpResponse(othercontent)
#微信伺服器推送訊息是xml的,根據利用ElementTree來解析出的不同xml內容返回不同的回覆資訊,就實現了基本的自動回覆功能了,也可以按照需求用其他的XML解析方法
import xml.etree.ElementTree as ET
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 = "您好,歡迎來到Python大學習!希望我們可以一起進步!"
replyMsg = TextMsg(toUser, fromUser, content)
print "成功了!!!!!!!!!!!!!!!!!!!"
print replyMsg
return replyMsg.send()
elif msg_type == 'image':
content = "圖片已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
elif msg_type == 'voice':
content = "語音已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
elif msg_type == 'video':
content = "視訊已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
elif msg_type == 'shortvideo':
content = "小視訊已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
elif msg_type == 'location':
content = "位置已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
else:
msg_type == 'link'
content = "連結已收到,謝謝"
replyMsg = TextMsg(toUser, fromUser, content)
return replyMsg.send()
except Exception, 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
import time
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)