如何将 WSGI 中的首选编码设置为 UTF-8

mli*_*ner 5 python apache mod-wsgi utf-8 python-3.x

感觉这里有点疯狂。我已经使用 mod_wsgi 设置了 Apache,但我无法使编码正常工作。我有:

  • 测试 mod_wsgi 是否在守护进程模式下运行
  • 请阅读Graham Dumpleton 的关于设置指令的博客文章。langlocaleWSGIDaemonProcess
  • 创建了一个似乎可以证明问题的最小测试
# I recompiled the mod_wsgi file to get the Python version correct
sys.version = '3.8.6 (default, Sep 24 2020, 21:54:23) \n[GCC 8.3.0]'
sys.prefix = '/usr/local'
sys.path = ['/usr/local/lib/python38.zip', '/usr/local/lib/python3.8', '/usr/local/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/site-packages', '/usr/local/src/scorched']

# This seems to be a timing thing? Not sure, but possibly problematic
locale.getlocale() = (None, None)
# This was fixed by setting lang or locale (not sure which)
locale.getdefaultlocale() = ('en_US', 'UTF-8')
sys.getdefaultencoding() = 'utf-8'

# These seem like a problem...
sys.getfilesystemencoding() = 'ascii'
locale.getpreferredencoding(False): 'ANSI_X3.4-1968'

# It's daemon mode
mod_wsgi.process_group = 'cl'
Run Code Online (Sandbox Code Playgroud)

我的 WSGI 配置如下所示:

    WSGIScriptAlias / /opt/courtlistener/docker/apache/wsgi-configs/python_version_test.py
    WSGIDaemonProcess cl \
      threads=10 \
      processes=64 \
      python-path=/usr/local/lib/python3.8/site-packages/ \
      lang='en_US.UTF-8' \
      locale='en_US.UTF-8'
    WSGIProcessGroup cl
    WSGIApplicationGroup %{GLOBAL}
    WSGIPassAuthorization On
Run Code Online (Sandbox Code Playgroud)

当我登录服务器并python在终端中启动时,此行工作正常,但通过 mod_wsgi 运行时失败:

from reporters_db import REPORTERS
Run Code Online (Sandbox Code Playgroud)

该行所做的只是导入一个 json 文件,其中包含一些 utf-8 内容。这是导入背后的代码:

# I recompiled the mod_wsgi file to get the Python version correct
sys.version = '3.8.6 (default, Sep 24 2020, 21:54:23) \n[GCC 8.3.0]'
sys.prefix = '/usr/local'
sys.path = ['/usr/local/lib/python38.zip', '/usr/local/lib/python3.8', '/usr/local/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/site-packages', '/usr/local/src/scorched']

# This seems to be a timing thing? Not sure, but possibly problematic
locale.getlocale() = (None, None)
# This was fixed by setting lang or locale (not sure which)
locale.getdefaultlocale() = ('en_US', 'UTF-8')
sys.getdefaultencoding() = 'utf-8'

# These seem like a problem...
sys.getfilesystemencoding() = 'ascii'
locale.getpreferredencoding(False): 'ANSI_X3.4-1968'

# It's daemon mode
mod_wsgi.process_group = 'cl'
Run Code Online (Sandbox Code Playgroud)

由于上面的 json 调用没有指定编码,因此它使用 ASCII 并失败:

 Traceback (most recent call last):
   File "/opt/courtlistener/docker/apache/wsgi-configs/python_version_test.py", line 6, in <module>
     from reporters_db import REPORTERS
   File "/usr/local/lib/python3.8/site-packages/reporters_db/__init__.py", line 22, in <module>
     REPORTERS = json.load(f, object_hook=datetime_parser)
   File "/usr/local/lib/python3.8/json/__init__.py", line 293, in load
     return loads(fp.read(),
   File "/usr/local/lib/python3.8/encodings/ascii.py", line 26, in decode
     return codecs.ascii_decode(input, self.errors)[0]
 UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 441720: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

我怎样才能告诉它(以及我的代码库的其余部分)像理智的成年人一样使用 utf-8 ?


编辑1

也许值得一提的是我正在使用以下命令运行 apache:

exec apache2ctl -D FOREGROUND "$@"
Run Code Online (Sandbox Code Playgroud)

我认为这会获取该/etc/apache2/envvars文件,因此我将以下内容附加到该文件中:

export LANG="en_US.UTF-8"
Run Code Online (Sandbox Code Playgroud)

我尝试将启动命令调整为:

LANG="en_US.UTF-8" exec apache2ctl -D FOREGROUND "$@"
Run Code Online (Sandbox Code Playgroud)

我满怀希望,但没有。还是没有进展。

mli*_*ner 5

好吧,我通过搜索每次 Graham Dumpleton 在互联网上提到“lang”这个词的时间,终于弄清楚了这一点。最终出现了这个线程,其中提到可能没有安装区域设置。我可以通过locale -a在我的 Ubuntu Docker 镜像中运行来检查这一点,结果显示:

locale -a
C
C.UTF-8
POSIX
Run Code Online (Sandbox Code Playgroud)

所以这就是问题所在!mod_wsgi当我请求时不知道我在请求什么en_US.utf-8,并且它也不会抛出错误。将我的设置更改为C.UTF-8立即修复此问题。

我正在运行一个精简的 docker 映像,所以这一定是我缺少语言环境的原因。我也没有/etc/default/locale这个一般领域的许多其他答案所引用的文件。

我已将此作为错误提交。


小智 5

在 Debian 11、Apache2、mod_wsgi 上解析包含 Unicode 字符的 yaml 文件时,我遇到了类似的 UnicodeDecodeError 问题。

将 WSGIDaemonProcess 区域设置设置为 C.UTF-8 就足够了,然后错误就消失了。这一行在我的 /etc/apache2/sites-available/000-default.conf 中更改

     WSGIDaemonProcess my_app locale='C.UTF-8'
Run Code Online (Sandbox Code Playgroud)

在问题中,mlissner 提到尝试了很多设置,但我不需要这些设置。