細數Python Flask微信公衆號開發中遇到的那些坑

最近兩三個月的時間,斷斷續續邊學邊作完成了一個微信公衆號頁面的開發工做。這是一個快遞系統,主要功能有用戶管理、寄收件地址管理、用戶下單,訂單管理,訂單查詢及一些宣傳頁面等。本文主要細數下開發過程當中遇到的各類坑,也算是另一種總結吧。

1. 開發語言及框架

Python + Flask + Bootstrap,數據庫使用的是MySQL
 

2. 相關文檔及Lib庫

1) Bootstrap官方文檔 http://v3.bootcss.com/getting-started/
2) 微信公衆號開發文檔 https://mp.weixin.qq.com/wiki
4) PDF 《FlaskWeb開發:基於Python的Web應用開發實戰》

3. 那些坑

3.1 微信

3.1.1 微信登錄

首先你須要仔細閱讀官方文檔,簡單來講微信登錄有以下幾步:
1) 生成微信認證跳轉URL,注意有`snsapi_base`跟`snsapi_userinfo`兩種方式,前者是靜默受權只獲取用戶openid,後者須要用戶手動贊成獲取用戶基本信息
2) 獲取access_token
3) 獲取用戶信息
 
解決微信OAuth2.0網頁受權只能設置一個回調域名的問題,參考 https://github.com/HADB/GetWeixinCode
Python微信SDK,參考 https://github.com/zwczou/weixin-python/

3.1.2 模版消息

登錄微信公衆平臺 -> 功能 -> 模版消息,選擇右側模版消息接口文檔 ,便可查看詳細的接口文檔。
主要步驟以下:
1)獲取access_token,其中token有效期爲7200s,並且微信限制了天天的調用次數,這裏使用functools.lru_cache維護了一個token的內存緩存
2)獲取模版ID
3)請求接口
POST URL: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
POST Data: 請求包爲json
 

3.2 MySQL

3.2.1 編碼問題

MySQL遇到最大的坑仍是編碼問題,由於涉及到獲取微信用戶名含有各類emoji表情的問題,須要設置字符編碼爲utf8mb4,具體能夠參考這篇文章( https://mathiasbynens.be/notes/mysql-utf8mb4),然而設置成功在Flask SQLAlchemy配置app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost:3306/test?charset=utf8mb4'後,運行報錯sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (2019, "Can't initialize character set utf8mb4 (path: C:\\mysql\\\\share\\charsets\\)"),解決無果。
最終解決方案是:
1) Flask SQLAlchemy配置app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost:3306/test?charset=utf8'
2) 微信用戶名寫入數據庫時使用repr()方法將寫入原始unicode字符,讀取的時候再使用eval()進行轉換
 

3.2.2 SQLAlchemy查詢數據轉換爲Dict

for u in session.query(User).all():
    u = dict(u.__dict__)
    u.pop('_sa_instance_state', None)
參考文章:
 

3.4 Flask

3.4.1 cookie相關

1) 設置cookie
@app.route('/set_cookie')
def set_cookie():
    response=make_response('Hello World');
    response.set_cookie('Name','Joo')
    return response
 
2) 獲取cookie
@app.route('/get_cookie')
def get_cookie():
    name=request.cookies.get('Name')
    return name
 
3) 刪除cookie
 
設置過時時間爲0
@app.route('/del_cookie')
def del_cookie():
    response=make_response('delete cookie')
    response.set_cookie('Name','',expires=0)
    return response
 
使用delete_cookie方法
@app.route('/del_cookie')
def del_cookie():
    response=make_response('delete cookie')
    response.delete_cookie('Name')
    return response
 

3.4.2 flask.make_response() 實例

3.4.3 詳細解讀Jquery各Ajax函數:$.get(),$.post(),$.ajax(),$.getJSON()

3.4.4 bootstrap對話框插件

3.4.5 Flask flash增長link

3.4.6 HTML顏色編碼

3.4.7 Python緩存

微信獲取access_token時有效期是7200s,並且微信限制了天天的調用頻率(2000次/天),因此簡單使用lru_cache在內存中維護了一個token緩衝,示例代碼以下:css

@lru_cache(None)
def getAccessToken():
    url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}'.format(app_id, app_secret)
    r = requests.get(url)
    access_token = r.json().get('access_token')
    time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print '[{0}] getAccessToken Result:\t{1}'.format(time_now, r.text)
    return access_token, datetime.now()


def getToken():
    token, t = getAccessToken()
    if (datetime.now() - t).seconds > 3600:
        getAccessToken.cache_clear()
        token, t = getAccessToken()
        return token
    else:
        return token

參考:html

 

3.4.8 修改Bootstrap使用國內源

因爲默認Bootstrap使用的CDN是http://cdnjs.cloudflare.com,國內訪問較慢,因此須要修改默認CDN爲國內源。
找到C:\Python27\Lib\site-packages\flask_bootstrap\__init__.py(C:\Python27 爲你當前Python版本路徑),在文件最後找到以下代碼:
        bootstrap = lwrap(
            WebCDN('//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/%s/' %
                   BOOTSTRAP_VERSION), local)

        jquery = lwrap(
            WebCDN('//cdnjs.cloudflare.com/ajax/libs/jquery/%s/' %
                   JQUERY_VERSION), local)

        html5shiv = lwrap(
            WebCDN('//cdnjs.cloudflare.com/ajax/libs/html5shiv/%s/' %
                   HTML5SHIV_VERSION))

        respondjs = lwrap(
            WebCDN('//cdnjs.cloudflare.com/ajax/libs/respond.js/%s/' %
                   RESPONDJS_VERSION))
替換爲國內源cdn.bootcss.com,代碼以下:
        bootstrap = lwrap(
            WebCDN('//cdn.bootcss.com/twitter-bootstrap/%s/' %
                   BOOTSTRAP_VERSION), local)

        jquery = lwrap(
            WebCDN('//cdn.bootcss.com/jquery/%s/' %
                   JQUERY_VERSION), local)

        html5shiv = lwrap(
            WebCDN('//cdn.bootcss.com/html5shiv/%s/' %
                   HTML5SHIV_VERSION))

        respondjs = lwrap(
            WebCDN('//cdn.bootcss.com/respond.js/%s/' %
                   RESPONDJS_VERSION))
參考資料:
 

3.4.9 flask部署

flask一般在Linux上部署方式是 flask + wsgi + nginx,windows上則是flask + iis + nginx。這裏實際部署的環境是Windows Server 2007,因爲項目實際訪問量較小的關係,最終選用簡單的flask + tornado部署方式。
在flask項目裏原來的入口程序假設爲run.py的同級目錄添加tornado_server.py,內容以下:
# coding:utf-8
 
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from run import app
http_server = HTTPServer(WSGIContainer(app))

# address爲實際訪問URL,port爲端口號
http_server.listen(port=5000, address="127.0.0.1")
IOLoop.instance().start()
使用python tornado_server.py便可啓動。
 
參考文檔:
相關文章
相關標籤/搜索