Django应用在Apache与开发服务器中编码不一致问题排查
环境配置
- Django: 4.0.5
- Python: 3.9.2
- Debian: 11.1
- Apache2: 2.4.53-1~deb11u1
- libapache2-mod-wsgi-py3: 4.7.1-3+b1
- mariadb-server-10.5: 1:10.5.15-0+deb11u1
问题现象
同一代码在开发服务器中运行无报错,但部署到Apache2后,执行以下代码时出现编码错误:
strx = 'sth %s' % name f = open('/tmp/somerandomfile', 'w') f.write(strx)
其中name变量来自数据库,包含本国语言字符。
两个环境下的输出差异:
- 开发服务器控制台输出:
print(strx, type(strx)) Kiadások <class 'str'> - Apache日志输出:
print(strx, type(strx)) Kiad\xc3\xa1sok <class 'str'>
开发服务器返回200状态码,Apache则抛出错误:
UnicodeEncodeError: 'ascii' codec can't encode character '\\xe1' in position 5: ordinal not in range(128)
关键差异发现
查看文件对象的编码属性,发现核心差异:
- 开发服务器:
'f': <_io.TextIOWrapper name='/tmp/tmplnrhh7np' mode='w' encoding='UTF-8'> - Apache环境:
'f': <_io.TextIOWrapper name='/tmp/tmpw3jl3sk2' mode='w' encoding='ANSI_X3.4-1968'>
Apache创建文件时默认使用ANSI_X3.4-1968(即ASCII)编码,导致无法写入非ASCII字符。
相关配置文件
Apache站点配置(sites-enabled/gyuser.conf)
<VirtualHost *:80> ServerName 127.0.0.25 ServerAlias Servernames DocumentRoot /usr/share/gyuser <Directory /usr/share/gyuser> Order allow,deny Allow from all </Directory> WSGIDaemonProcess gyuser.djangoserver user=gyuser processes=10 threads=20 display-name=%{GROUP} python-path=/usr/share/gyuser:/home/gyuser/.virtualenvs/gyuser/lib/python3.9/site-packages WSGIProcessGroup gyuser.djangoserver WSGIScriptAlias / /usr/share/gyuser/gyuser/wsgi.py CustomLog ${APACHE_LOG_DIR}/gyuser-access.log combined ErrorLog ${APACHE_LOG_DIR}/gyuser-error.log LogLevel debug
wsgi.py代码
import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gyuser.settings") application = get_wsgi_application()
问题原因
Python的默认文件编码由系统环境变量决定:
- 开发服务器在终端环境运行,终端的
LANG/LC_ALL等变量设置为UTF-8,Python继承该配置,因此默认用UTF-8打开文件。 - Apache的WSGI守护进程运行时,未加载用户的locale配置,默认使用ASCII编码(ANSI_X3.4-1968),导致写入含非ASCII字符的字符串时触发编码错误。
解决方法
方法1:显式指定文件编码(最稳妥)
打开文件时直接指定encoding='utf-8',不依赖环境配置:
f = open('/tmp/somerandomfile', 'w', encoding='utf-8')
方法2:配置Apache WSGI进程的locale环境
在Apache的WSGIDaemonProcess指令中添加env参数,指定UTF-8编码的locale(以匈牙利语hu_HU.UTF-8为例,可根据实际语言调整):
WSGIDaemonProcess gyuser.djangoserver user=gyuser processes=10 threads=20 display-name=%{GROUP} python-path=/usr/share/gyuser:/home/gyuser/.virtualenvs/gyuser/lib/python3.9/site-packages env=LANG=hu_HU.UTF-8
修改后重启Apache生效:systemctl restart apache2
方法3:在wsgi.py中设置环境变量
在wsgi.py开头添加环境变量设置,强制指定UTF-8 locale:
import os # 设置UTF-8 locale os.environ['LANG'] = 'hu_HU.UTF-8' os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gyuser.settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application()
补充:确保系统已安装对应locale
执行locale -a查看系统已安装的locale,如果目标locale(如hu_HU.UTF-8)不存在,运行以下命令安装:
dpkg-reconfigure locales
在弹出的界面中勾选对应locale并确认。
内容的提问来源于stack exchange,提问作者user2194805
相关产品推荐
相关产品推荐

