內容轉載自我自己的博客
代碼已上傳Github倉庫 https://github.com/zfb132/wechatPlatform
@
准備工作
首先,申請一個屬於自己的微信公眾號(必須保證全局管理員是自己的微信賬戶,否則會很麻煩),還要擁有自己的服務器(Ubuntu 系統)來部署代碼,且服務器已經成功安裝了網絡相關的兩個常用軟件 uwsgi 和 nginx ,前者一般用於進程控制,后者用於反向代理。
服務器端部署流程
第一步,在 Ubuntu 系統安裝 venv :
sudo apt-get install python3-venv
第二步,創建 Python3 的虛擬環境:
python3 -m venv myvenv
注意:source myvenv/bin/activate
表示激活虛擬環境,deactivate
退出虛擬環境
第三步,在虛擬環境中升級pip:
pip install --upgrade pip
然后安裝requirements.txt
文件內的模塊:
pip install -r requirements.txt
第四步:主代碼的編寫,主要有兩種方法:
一種方法,直接下載我已經寫好的代碼運行即可:
git clone git@github.com:zfb132/wechatPlatform.git
另一種方法,自己逐個創建代碼,創建所有代碼后的目錄文件結構如下:
wechatPlatform/
wechatPlatform/app/
wechatPlatform/app/__init__.py
wechatPlatform/app/config.py
wechatPlatform/app/controller/
wechatPlatform/app/controller/main.py
wechatPlatform/log.py
wechatPlatform/requirements.txt
wechatPlatform/runserver.py
各文件內容附在文章的最后。其中,要把config.example.py
文件重命名為config.py
,然后把里面的token
改成自己的
第五步,編輯nginx.conf
文件:
sudo vi /etc/nginx/nginx.conf
在合適位置添加以下內容:
server{
listen 80;
server_name xxxx.whuzfb.cn;
access_log /home/ubuntu/wechatPlatform/log/access.log;
error_log /home/ubuntu/wechatPlatform/log/error.log;
location /{
include uwsgi_params;
uwsgi_pass 127.0.0.1:8111;
proxy_pass http://127.0.0.1:8111/;
}
}
然后再重啟 nginx 服務:
service nginx restart
最后啟動本代碼在后台運行:
uwsgi uwsgi_wechat.ini -d ./server.log
至此,服務器端的代碼已經全部編寫並部署完成
注意:在啟動uwsgi后會生成四個進程監聽8111端口,如果想要殺死他們,先查看占用8111端口的所有進程的ID(不能直接關閉uwsgi,這可能會影響到其他項目),終端輸入lsof -i:8111
命令即可查看,然后使用kill -9 id
依次殺死各個進程;這種方法比較麻煩,另一種快速的方法是:
kill -9 $(lsof -t -i:8111)
此命令可一步到位殺死所有占用8111端口的進程
微信平台網頁端配置
瀏覽器打開微信公眾平台登錄自己的管理員賬戶,點擊開發
欄目,選擇基本配置
,根據網頁提示填寫這三個內容(一般選擇明文模式):
需要注意的是,一定要先在服務器端把代碼運行起來,這樣才能成功保存網頁端的配置
附錄
log.py
文件內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import logging
from logging.handlers import RotatingFileHandler
LOG_FORMAT = "%(asctime)s [%(funcName)s: %(filename)s,%(lineno)d] - %(levelname)s : %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S"
LOG_PATH = "./log/"
# 初始化日志文件配置
def initLog(fileName,logger):
# 創建日志文件夾
if not os.path.exists(LOG_PATH):
os.mkdir(LOG_PATH)
myapp = logging.getLogger(logger)
myapp.setLevel(logging.DEBUG)
# 切割日志文件
handler = RotatingFileHandler(LOG_PATH+fileName, maxBytes=128*1024,backupCount=60)
handler.setFormatter(logging.Formatter(LOG_FORMAT,DATE_FORMAT))
myapp.addHandler(handler)
return myapp
runserver.py
文件內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import app
from log import initLog
logging = initLog('wechat.log','runserver')
if __name__ == '__main__':
app.run(debug=True,port=8111)
application = app
config.py
文件內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
DEFAULTMESSAGE = "你好,消息已收到"
token = "mytoken"
__init__.py
文件內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
import logging
import os
app = Flask(__name__)
app.secret_key = "thisissecretkey"
from app.controller.main import *
main.py
文件內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import app
from flask import request
import app.config as config
import logging
from wechatpy.utils import check_signature
from wechatpy.exceptions import InvalidSignatureException
from wechatpy import parse_message
from wechatpy.replies import TextReply
from wechatpy.replies import ImageReply
logging = logging.getLogger('runserver.main')
def handlemsg(data):
msg = parse_message(data)
print(msg)
logging.debug('handle msg:'.format(msg))
xml = txtreply(msg,msg.content)
return xml
# 微信消息接口
@app.route('/',methods=["POST","GET"])
def main():
logging.debug('進入主頁面')
try:
signature = request.args.get("signature", "")
timestamp = request.args.get("timestamp", "")
nonce = request.args.get("nonce", "")
echostr = request.args.get("echostr", "")
# echostr是微信用來驗證服務器的參數,需原樣返回
if echostr:
try:
logging.debug('正在驗證服務器簽名')
check_signature(config.token, signature, timestamp, nonce)
logging.debug('驗證簽名成功')
return echostr
except InvalidSignatureException as e:
logging.error('檢查簽名出錯: '.format(e))
return 'Check Error'
# 也可以通過POST與GET來區別
# 不是在進行服務器驗證,而是正常提交用戶數據
logging.debug('開始處理用戶消息')
xml = handlemsg(request.data)
return xml
# 處理異常情況或忽略
except Exception as e:
logging.error('獲取參數失敗: '.format(e))
def imgreply(msg,id):
reply = ImageReply(message=msg)
reply.media_id = id
xml = reply.render()
return xml
def txtreply(msg,txt):
reply = TextReply(content=txt, message=msg)
xml = reply.render()
return xml
uwsgi_wechat.ini
文件內容:
[uwsgi]
# http協議對客戶端開發的端口號
http = 0.0.0.0:8111
# 應用目錄,即python代碼所在目錄
pythonpath = ./
# web 應用python主程序
wsgi-file = ./runserver.py
# 一般在主運行程序里指定 app = Flask(__name__)
callable = app
# 工作進程數
processes = 4
# 線程數
threads = 2
# 指定日志文件
demonize = ./server.log
# python 虛擬環境目錄
home = ./myvenv
后記
雖然目前這個代碼只是把用戶發來的消息再原封不動的返回給用戶,看起來好像折騰了半天並沒有實現啥有趣的功能,但是它最少實現了解析用戶發來的消息以及返回給用戶文字消息的功能,這已經足夠了。消息處理的邏輯可以自己繼續慢慢完善,比如接入圖靈機器人等有趣功能