问题:
Python3其实是默认使用unicode(UTF-8)编码的,但是当使用uWSGI来部署应用并且用supervisor作进程守护的时候,就会出现编码问题,比较典型的是用于检查的print命令报UnicodeEncodingError,内容是有字符无法用ASC II编码。
UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-5: ordinal not in range(128)
分析:
经过一轮google,怀疑问题出在系统环境的locale设置上,然而在修改了LC_ALL、LC_LANG等等系统常量后重启仍然没有问题。在已经成功部署的应用代码中检查环境变量,发现sys.stdout.encoding居然是“ANSI_X3.4-1968”而不是“UTF-8”。这样的错误在python命令行解析器中是无法重现的,因此怀疑是解析器的设置和uWSGI或者supervisor的环境参数有冲突,选择了服从调用者的参数设置。
解决:
又google了一下,有人在程序中使用
sys.stdout=io.TextIOWrapper(sys.stdout.buffer, encoding=‘utf-8’)
来强制修改sys.stdout.encoding的值,但是也指出这样并不彻底。在碰到有python模块override这个buffer设置使用默认编码的情况下,还是会出错。于是想到了修改uWSGI或者supervisord的默认编码设置。按这个思路google的时候,发现uWSGI并没有关于编码的设置,验证了一下,不使用supervisor直接用uwsgi XXX.ini的方式部署服务是不会出现编码错误的,说明问题很可能出在supervisor这个用Python2.7写的进程管理器上。要解决这个问题,只需要在supervisor的supervisord.conf文件的[supervisord]标签下增加一行:
[supervisord]
environment=LC_ALL=’en_US.UTF-8′,LANG=’en_US.UTF-8′
重启supervisor服务之后,一切正常了。
总结:
由于supervisord是用Python2.7写的,supervisor的环境参数默认值按照Python2的默认值设定,而默认字符编码是asc ii,而supervisor又处于这个部署方案的最底层,所以它的环境参数就override了Python3解释器的默认值。因此,这种牵涉到多个组成部分的部署方案,要特别注意运行时环境的定义,最好能显式设定各环境参数。