問題
最近公司購買了阿里雲,預裝的ubuntu1404,上面自帶Apache2.4,計劃安裝Flask,需要通過wsgi適配,於是看到了這篇文章,按照上面的方法搭建成功
進一步豐富業務邏輯時,發現如果瀏覽器提交的表單數據包含中文字符,則Flask會報unicode錯誤
UnicodeEncodeError: 'ascii' codec can't encode characters in position
排查過程
但是我記得Flask默認支持unicode的,通過腳本啓動Flask自身的簡易HTTP server也印證了這一點,所以問題出在apache或mod_wsgi,apache的字符編碼相關配置在/etc/apache2/conf-enabled/charset.conf文件,但打開下面這一行開關後也無效
# AddDefaultCharset UTF-8
再尋找mod_wsgi的字符編碼相關配置文件,沒找到,最接近的是/etc/apache2/mods-enabled/wsgi.conf,但裏面也有任何字符編碼相關的選項
決定深挖WSGI,閱讀其設計方案文檔PEP 333,發現Unicode Issues一節有這麼一段話
HTTP does not directly support Unicode, and neither does this interface. All encoding/decoding must be handled by the application
說明mod_wsgi並不關心編碼,問題排查貌似走到了死衚衕,但是既然mod_wsgi不是問題所在,那apache肯定還有什麼地方有問題
解決方案
經過一番摸索,發現/etc/apache2/envvars文件裏有這麼一段
## The locale used by some modules like mod_dav
export LANG=C
## Uncomment the following line to use the system default locale instead:
#. /etc/default/locale
原來apache默認是ascii編碼,而且很可能影響mod_wsgi!我的ubuntu系統雖然是英文的,但也是en_US.UTF-8編碼,因爲/etc/default/locale文件的內容是
LANG="en_US.UTF-8"
LANGUAGE="en_US:"
將envvars文件上述段落的第二行註釋掉,第四行打開,重啓apache服務,一切正常
心得
apache是以www-data用戶運行的,沒有登陸shell,環境變量不能在rc文件裏設置,所以環境變量是通過讀取envvars文件實現的
mod_wsgi類似於mod_python,是一個將python語言和apache運行環境連接起來的binding,負責的內容包括類型映射,IO映射等,它並不是一個縮水版的python解釋器,所以不關心字符編碼之類的環境變量