我有一个Flask应用程序(Linux,带有mod_wsgi的Apache,Python 3),它使用一些参数调用shell脚本。当subprocess.run()
命令参数中有任何非ascii字符时,应用程序中会出现以下错误:
'ascii'编解码器无法编码5-6位的字符:序数不在范围内(128)
我花了很多时间来修复它。
命令行中不存在此类问题,仅在应用程序中存在。
整个应用程序的输出是Unicode,并没有任何问题。经过一些研究后,我得出结论,问题在于“文件系统编码”。
我在我的run.wsgi
脚本中添加了一些日志记录语句。 FS编码确实是'ascii'(在命令行中是'utf-8')。
在下一步中,我发现了这篇文章How to change file system encoding via python?
Apache httpd服务器是在其环境中使用LANG=C
启动的。尽管在C.UTF-8
警告,我已将其更改为/etc/sysconfig/httpd
。这没有帮助,FS编码仍然是'ascii'。然后我甚至将sys.getfilesystemencoding()
猴子修补到lambda: 'utf-8'
。但错误仍然存在。
每次更改后我都正确地重新启动了httpd服务。
我的智慧结束了。
UPDATE1:
代码段:
import subprocess as sub
cmdresult = sub.run(
[SCRIPT, tid, days, name],
stdin=sub.DEVNULL, stdout=sub.PIPE, stderr=sub.DEVNULL,
encoding='ascii', # 'utf-8' will not help, this affects stdin, stdout I/O only
check=True)
在mod_wsgi的上下文中,您应确保使用mod_wsgi守护程序模式并为mod_wsgi守护程序进程组设置lang / locale。有关更详细的说明,请在此处重复,请参阅:
(回答自己的问题,希望对别人有帮助)
我做了一个简短的测试程序。这是我发现的:
LANG=C.UTF-8
需要安装区域设置,它不在我的系统上(使用locale -a
检查)。但是在第二个可用的系统上,它可以工作。cmdresult = sub.run(
[SCRIPT, tid, days, name.encode('utf-8')],
...
这是有效的,但有一个问题是:
它符合文档吗?
我能找到的是:
args应该是一系列程序参数或者是一个单独的字符串
我确实把它理解为一个字符串或一个字符串列表,但实际上并没有指定什么类型的列表。我也通过了int来看看会发生什么。我收到了这个错误:
expected str, bytes or os.PathLike object
所以我的解决方案似乎很好。