概述
在本(ben)教程中,您將學會使(shi)用彈(dan)性云(yun)主機(以下簡稱(cheng) ECS)搭建微信公眾號處理(li)后(hou)臺(tai),使(shi)用Python語言編寫對應的(de)微信消息處理(li)邏輯代碼,接收(shou)從微信服務端轉(zhuan)發過來的(de)消息,并返(fan)回處理(li)結果給最終用戶(hu)。

您需要了解(jie)的(de)背景(jing)知(zhi)識有(you): CentOS(Linux)操作系統(tong)、Python語言、Web.py框架、HTTP/XML協議。
準備事項
1、申請微信公眾號
微(wei)信公眾號申請鏈接:
2、購買天翼云彈性云服務。
本教程(cheng)中,以“云圖說”為例,使(shi)用公(gong)共鏡(jing)像CentOS 7.4。
3、購買彈性IP
建(jian)議同時購買彈(dan)性IP,后面需(xu)要(yao)在微信公(gong)(gong)眾號上配(pei)置公(gong)(gong)網IP的地址。
安裝基礎軟件
本(ben)(ben)教(jiao)程(cheng)中使(shi)用Python+Web.py組合完(wan)成微信公眾號(hao)開發,需(xu)要安(an)裝或升(sheng)級Python、pip、Web.py框架、WinSCP軟件版本(ben)(ben)。
升級默認Python版本
CentOS 7.4自(zi)帶Python版本(ben)比較(jiao)老,建議(yi)升級到Python3。
1、查看Python版本,使(shi)用(yong)如下(xia)命(ming)令:
python --version

2、下載Python安裝包,這里以Python 3.6.0版(ban)本為例,使用命令(ling):
wget //www.python.org/ftp/python/3.6.0/Python-3.6.0a1.tar.xz

3、解壓安裝包(bao),使(shi)用如下命令:
tar xvf Python-3.6.0a1.tar.xz
4、執行命令:
cd Python-3.6.0a1
./configure

- 如果出現“configure: error: no acceptable C compiler found in $PATH”異常提示,是因為未安裝合適的編譯器。
解決方法:
執行以下命令,安裝/升級gcc及其他依賴的包。
sudo yum install gcc-c++
并在隨后提(ti)示安裝包是否OK時(shi),輸(shu)入(ru)y并回車。出現(xian)如下圖提(ti)示說明依(yi)賴的包安裝成功。

在編譯器(qi)安裝(zhuang)完成(cheng)后,重(zhong)新執行./configure命(ming)令。
5、執行命令:
make && make install
執(zhi)行(xing)成功。但提(ti)示pip錯誤,原因(yin)是我的系統中(zhong)少(shao)了openssl-devel包(bao),可以先忽略
6、查看Python3版本,使用(yong)命令:
python3 --version

7、執行命令:
python3
出現如下(xia)提示,則(ze)說(shuo)明Python3安裝成功。

說明
執行后續操作前需要先退出Python命令行,可通過輸入以下任一命令再按回車鍵退出:
- Ctrl+Z
- exit()
- quit()
升級默認pip版本
pip是通用的(de)Python包(bao)管(guan)理工(gong)具。提(ti)供了對Python包(bao)的(de)查(cha)找、下載(zai)、安(an)(an)(an)裝(zhuang)、卸載(zai)功(gong)能。Python3安(an)(an)(an)裝(zhuang)成(cheng)功(gong)后自帶pip3,但(dan)版本比較老,建議升級到pip最新(xin)版本。同時前面安(an)(an)(an)裝(zhuang)python3提(ti)示(shi)“Ignoring ensurepip failure: pip 8.1.1 requires SSL/TLS”錯誤,導致pip未成(cheng)功(gong)安(an)(an)(an)裝(zhuang),所以需要重新(xin)安(an)(an)(an)裝(zhuang)pip。
1、安裝(zhuang)openssl-devel包(bao),使(shi)用(yong)命令:
yum install openssl-devel -y

2、執行命令:
make && make install
出(chu)現如下(xia)提(ti)示說明安(an)裝pip安(an)裝成功。

3、升級(ji)pip3,使用命令:
pip3 install --upgrade pip
出現如下提示說明升級(ji)pip到最新版本了(le)。

安裝Web.py框架
Web.py官方教程地址://webpy.org/,使用如下命令安裝web.py:
pip3 install web.py==0.40.dev0

安裝WinSCP
通常情況下,我們(men)在本地(di)Windows操作(zuo)系(xi)統上編(bian)輯(ji)代碼,完成后再上傳至ECS上(CentOS Linux系(xi)統)。WinSCP 是一個(ge)Windows環境下使用的SSH的開源圖形化SFTP客戶端, 同時支持 SCP 協(xie)議。它(ta)的主要(yao)功(gong)能是在本地(di)與遠程計算機間安(an)全地(di)復制文(wen)(wen)件,并且(qie)可以直接(jie)編(bian)輯(ji)文(wen)(wen)件。
WinSCP安裝鏈接://winscp.net/eng/docs/lang:chs
上傳代碼
1、新建main.py文件,復制如下代碼(ma):
#?-*-?coding:?utf-8?-*-
#?filename:?main.py
import?web
from?handle?import?Handle
urls?=?(
????'/wx',?'Handle',
)
if?__name__?==?'__main__':
????app?=?web.application(urls,?globals())
????app.run()
2、新建handle.py文(wen)件,復制如(ru)下代(dai)碼:
#?-*-?coding:?utf-8?-*-
#?filename:?handle.py
import?hashlib
import?web
import?receive
import?time
import?os
class?Handle(object):
????def?__init__(self):
????????self.app_root?=?os.path.dirname(__file__)
????????self.templates_root?=?os.path.join(self.app_root,?'templates')
????????self.render?=?web.template.render(self.templates_root)
????def?GET(self):
????????try:
????????????data?=?web.input()
????????????if?len(data)?==?0:
????????????????return?"hello,?this?is?handle?view"
????????????signature?=?data.signature
????????????timestamp?=?data.timestamp
????????????nonce?=?data.nonce
????????????echostr?=?data.echostr
????????????token?=?"此處內容與公眾號基本配置里Token字段取值保持一致"
????????????list?=?[token,?timestamp,?nonce]
????????????list.sort()
????????????s?=?list[0]?+?list[1]?+?list[2]
????????????hashcode?=?hashlib.sha1(s.encode('utf-8')).hexdigest()
????????????print(?"handle/GET?func:?hashcode,?signature:?",?hashcode,?signature)
????????????if?hashcode?==?signature:
????????????????return?echostr
????????????else:
????????????????return?echostr
????????except?(Exception)?as?Argument:
????????????return?Argument
????def?POST(self):
????????try:
????????????webData?=?web.data()
????????????print("Handle?Post?webdata?is:\n",?webData)
????????????#打印消息體日志
????????????recMsg?=?receive.parse_xml(webData)
????????????if?isinstance(recMsg,?receive.Msg)?and?recMsg.MsgType?==?'text':
????????????????toUser?=?recMsg.FromUserName
????????????????fromUser?=?recMsg.ToUserName
????????????????content?=?"歡迎關注云圖說!"?+?str(recMsg.Content)
????????????????print('Reply?message?info:\n')
????????????????print('toUser?=',?toUser)
????????????????print('fromUser?=?',?fromUser)
????????????????print('content?=?',?content)
????????????????return?self.render.reply_text(toUser,?fromUser,?int(time.time()),?content)
????????????else:
????????????????print("不支持的消息類型:",recMsg.MsgType)
????????????????return?"success"
????????except?(Exception)?as?Argment:
????????????return?Argment
3、新(xin)建receive.py文件,復制如下代碼:
1.#?-*-?coding:?utf-8?-*-
2.#?filename:?receive.py
3.import?xml.etree.ElementTree?as?ET
4.
5.def?parse_xml(web_data):
6.????if?len(web_data)?==?0:
7.????????return?None
8.????xmlData?=?ET.fromstring(web_data)
9.????msg_type?=?xmlData.find('MsgType').text
10.????if?msg_type?==?'text':
11.????????return?TextMsg(xmlData)
12.????elif?msg_type?==?'image':
13.????????return?ImageMsg(xmlData)
14.????elif?msg_type?==?'location':
15.????????return?LocationMsg(xmlData)
16.????elif?msg_type?==?'event':
17.????????return?EventMsg(xmlData)
18.
19.class?Event(object):
20.????def?__init__(self,?xmlData):
21.????????self.ToUserName?=?xmlData.find('ToUserName').text
22.????????self.FromUserName?=?xmlData.find('FromUserName').text
23.????????self.CreateTime?=?xmlData.find('CreateTime').text
24.????????self.MsgType?=?xmlData.find('MsgType').text
25.????????self.Eventkey?=?xmlData.find('EventKey').text
26.
27.class?Msg(object):
28.????def?__init__(self,?xmlData):
29.????????self.ToUserName?=?xmlData.find('ToUserName').text
30.????????self.FromUserName?=?xmlData.find('FromUserName').text
31.????????self.CreateTime?=?xmlData.find('CreateTime').text
32.????????self.MsgType?=?xmlData.find('MsgType').text
33.????????self.MsgId?=?xmlData.find('MsgId').text
34.
35.class?TextMsg(Msg):
36.????def?__init__(self,?xmlData):
37.????????Msg.__init__(self,?xmlData)
38.????????self.Content?=?xmlData.find('Content').text
39.
40.class?ImageMsg(Msg):
41.????def?__init__(self,?xmlData):
42.????????Msg.__init__(self,?xmlData)
43.????????self.PicUrl?=?xmlData.find('PicUrl').text
44.????????self.MediaId?=?xmlData.find('MediaId').text
45.
46.class?LocationMsg(Msg):
47.????def?__init__(self,?xmlData):
48.????????Msg.__init__(self,?xmlData)
49.????????self.Location_X?=?xmlData.find('Location_X').text
50.????????self.Location_Y?=?xmlData.find('Location_Y').text
51.
52.class?EventMsg(Msg):
53.????def?__init__(self,?xmlData):
54.????????Event.__init__(self,?xmlData)
55.????????self.Event?=?xmlData.find('Event').text
4、新建templates文(wen)件夾,在文(wen)件夾下(xia)新建reply_text.xml文(wen)件,復制如下(xia)代碼:
$def?with?(toUser,fromUser,createTime,content)
<xml>
<ToUserName><![CDATA[$toUser]]></ToUserName>
<FromUserName><![CDATA[$fromUser]]></FromUserName>
<CreateTime>$createTime</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[$content]]></Content>
</xml>
5、最終本地代碼(ma)文件形成(cheng)如(ru)下:

6、通過WinSCP工具(ju)將上(shang)(shang)述文(wen)件與(yu)目錄上(shang)(shang)傳至ECS指定目錄下(xia):

啟動服務
使用如下命令啟動服務:
python3 main.py 80
啟(qi)動成功如下圖(tu)所(suo)示(shi):
、
啟用開發者模式
1、登錄微信公眾平臺,選擇“開發 >基本配(pei)置(zhi)(zhi)”,單(dan)擊“修改配(pei)置(zhi)(zhi)”。
2、填寫配置信息,單(dan)擊(ji)“提交”。
- URL://ECS的彈性公網IP/wx,不用添加80端口。
- Token:需要與handle.py中對應token取值完全一致。
- EncodingAESKey:隨機生成。
- 消息加解密方式:此為示例,選擇簡單的“明文模式”。
3、驗證token成功,單擊“啟用”。
說明
如果(guo)token驗證失(shi)敗,請檢(jian)查(cha)Token配置與(yu)handle.py中(zhong)GET消息(xi)處理代碼是(shi)否一致。
驗證
使用微信(xin)關注公眾(zhong)號,任意發送(song)一條文本消息(xi),看是(shi)否能(neng)夠收到(dao)回復。如(ru)能(neng)收到(dao)回復則表(biao)明系統(tong)處理(li)正常。