其實這個功能一早就完成了,但是直到今天才有空把它記錄下來~~
準備工作
在正式開始之前,需要做一些準備:
a: 安裝好wechat_sdk(怎麼安裝請看我前面寫<<基于Django的微信公衆号開發(2) -- 在sae添加第三方包>>);
b: 成功通過了微信公衆号的開發者認證;
c: 建立一個應用(不是必須的), 我建立了一個dict應用.
需要注意的事項
在正式動手之前,首先我要說一下要注意的事(我踩過的坑):
a: 微信公衆号伺服器在收到使用者在公衆号輸入的資訊之後, 隻會轉發到一個url上(就是你開發者認證時所填的那個url,是以隻能通過這個url來接收資訊)
b: 公衆号收到使用者的資訊之後, 将會把它打包成規定的xml的模式通過你注冊的url發送到你的伺服器上, 你發送給使用者的消息同樣要包裝成同樣格式的xml才能成功, 否則公衆号服 務器一律拒絕并在使用者端傳回"該公衆号提供的服務出現故障, 請稍後再試"的提示(幸運的是在wechat_sdk已經有打包這種xml的方法了, 如果你想了解, 你可以看看公衆号的開發文檔)
c: 傳回給使用者的文字一定要用utf-8格式
d: 每次發送的消息長度長度不能超過2048位元組, 由于采用utf-8編碼, 是以請留意每個漢字都算作3個位元組, 超長就要記得截斷發兩次了
調試技巧
無論你的伺服器在調試過程中出了什麼錯, 在使用者端都是提示"該公衆号提供的服務出現故障, 請稍後再試"的提示, 是以想隻靠一個測試賬号來調試明顯是很不靠譜的. 在公衆号平台上有一個調試 工具, 但是他也隻會傳回通路的錯誤代碼(200/500之類的), 并沒有給出提示, 同樣也是很不靠譜, 那麼我們該怎麼樣知道我的伺服器跟微信發送消息這部分出了什麼問題呢?
我在開發過程中發現了一個技巧, 我們的伺服器從公衆号伺服器接收了一個包含xml格式的包, 并且開始讀取處理, 最後把處理結果(傳回給使用者的文字)打包成xml包發送給公衆号伺服器. 原理是這樣子. 那麼我們隻要僞造一個使用者發送資訊的xml段, 儲存在一個xml檔案裡面, 需要用的時候就讀取這個xml檔案, 在背景控制台調試輸出包裝好的xml就行了 (當然你得先排除網絡連接配接的問題,因為網絡連接配接導緻你的伺服器接收不了,或者發送不了都有可能發生的,還有就是環境的問題,不過隻要你正确配置就不太可能這種問題的). 需要發送不同的資訊的時候, 寫個函數修改xml裡面的消息部分就可以了.
開發過程
首先, 我們現在可以把用于通過微信公衆号驗證的代碼給注釋掉了(最好不要删除), 然後我們建立一個相同名字的函數
下面是我的一些代碼(為了更了解整個基本的結構, 代碼有所删減, 主要是擷取資料部分跟格式組裝部分)
# 這是段代碼是我dict應用的傳回微信消息響應部分, 主要功能是擷取消息->做出對應反應->傳回消息
# 為了友善大家了解, 有一部分我将會用"(--tips--)"的格式進行簡化, 隻保留必要部分
# 代碼開始
# -*- coding: utf-8 -*-
# 這段是需要添加的,主要是為了添加path,保證django的正常運作
# (因為我的django用的是自己的包嘛)
import os
import sys
root = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(root, '../site-packages/Django-1.9.7-py2.7.egg'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'yuuuuchang.settings'
from django.shortcuts import render
from django.http.response import HttpResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from wechat_sdk import WechatBasic
from wechat_sdk.exceptions import ParseError
from wechat_sdk.messages import TextMessage, VoiceMessage, ImageMessage, VideoMessage, LinkMessage, LocationMessage, \
EventMessage
# (-- 個人資料的調用, 自定義傳回格式的組裝, 跟資料庫查詢的入口 --)
# wechat_sdk需要初始化一些資料
wechat = WechatBasic(token=WECHAT_TOKEN, appid=WEIXIN_APPID, appsecret=WEIXIN_APPSECRET)
# def wechat_message(request):
# """ 微信認證 """
# if request.method == 'GET':
# signature = request.GET.get('signature')
# timestamp = request.GET.get('timestamp')
# nonce = request.GET.get('nonce')
#
# if not wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
# return HttpResponseBadRequest('Verify Failed')
# else:
# return HttpResponse(request.GET.get('echostr', ''), content_type='text/plain')
def wechat_message(request):
""" 消息入口,使用者通過輸入框發送的消息都發到這裡處理 """
# 解析本次請求的 XML 資料
try:
wechat.parse_data(data=request.body)
except ParseError:
return HttpResponseBadRequest('無效的xml資料')
# 擷取解析好的微信請求資訊
message = wechat.get_message()
# 假如資訊是文本格式
# (TextMessage是wechat_sdk定義的一個文本消息類,下面還有語音類之類的,經過上面解析的消息都會歸屬到這些類中)
if isinstance(message, TextMessage):
context = message.content.strip()
# 假設使用者輸入的是什麼文字,然後做出相應反應
if context == '筆記' or context == 'blog':
tips = '這裡設定你需要發給使用者的文字'
elif context == '學習' or context == 'study':
tips = '這裡設定你需要發給使用者的文字'
elif context == 'help':
tips = '這裡設定你需要發給使用者的文字'
else:
# (-- 擷取到context, 并且用這個context作為查詢條件在資料庫中查找相應結果 --)
# (-- 如果你也有從資料庫擷取資料然後傳回的操作,記得把結果轉utf-8格式 --)
# 沒有查詢結果
if len(foundword) == 0:
tips = '未查詢到結果,換個詞試試?'
# 查詢到一個
elif len(foundword) == 1:
# (-- 将結果用自定義的格式打包好(主要是換行跟縮進),然後放到tips裡面 --)
# 查詢到多個結果
else:
# (-- 将結果用自定義的格式打包好(主要是換行跟縮進),然後放到tips裡面 --)
# 如果收到語音資訊
if isinstance(message, VoiceMessage):
tips = '打字啦,語音消息我聽不懂~'
# 如果收到圖檔資訊(下面看提示就知道了,不多說)
if isinstance(message, ImageMessage):
tips = '雖然有點看不懂~但是我喜歡這張圖!'
if isinstance(message, VideoMessage):
tips = '這個是..視訊消息?怎麼打開教教我嘛~'
if isinstance(message, LinkMessage):
tips = '不要發奇怪的位址給我,我真的看不懂咧'
if isinstance(message, LocationMessage):
tips = '這個...哪邊是北?(路癡專用懵X表情)'
# 這裡是定義使用者對公衆号所做的事(事件,比如關注,取消關注等)
if isinstance(message, EventMessage):
# 公衆号被關注的時候
if message.type == 'subscribe':
tips = '''感謝你關注"魚腸筆記"! balabala...'''
else:
(-- 省略 --)
# 最後, 經過前面諸多處理, 我們得出了一個tips的文本資訊, 這就是我們想對使用者說的, 我們需要打包, 然後以規定格式傳回
# 首先是打包, wechat_sdk已經做了一個方法了
result = wechat.response_text(content=tips)
# 然後是傳回,記得規定是xml格式傳回
return HttpResponse(result, content_type='application/xml')
基本上的要點就是這樣了, 太偏遠的我已經剔除掉
你可以下手玩玩, 祝你玩得愉快~
以上!