細數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緩沖,示例代碼如下:

@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

參考:

 

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即可啟動。
 
參考文檔:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM