[求大神解答] Django 项目部署到线上后出现编码问题

2018-06-26 12:03:49 +08:00
 watermelon92

一、项目说明:

用户上传一个压缩文件(内含 html 文件夹),网站解压文件并保存至指定目录,供外部直接访问静态 html 文件。

二、问题:

解压文件时报错:UnicodeEncodeError: 'ascii' codec can't encode characters,具体信息见链接:报错信息

三、尝试思路

  1. 代码在本地,macos 下可解压含中文的文件。
  2. 在线上解压英文 html 文件也是正常的。
  3. 报错的代码单独在 ubuntu 下运行正常,可以创建文件。
  4. google 了所有关键词,基本都是 2.7 的解决方案,在项目里使用无效。
  5. 找到一个类似的问题,可能由 ubuntu 系统语言原因导致。原问题链接

四、出错代码块:

def handle_uploaded_file(f, num, new_dir_name):
    release_file_dir = os.path.join(UPLOAD_FILES_DIR, str(num))
    new_dir = os.path.join(release_file_dir,new_dir_name)
    filePath = f
    with zipfile.ZipFile(filePath, 'r') as zf:
        for fn in zf.namelist():
            right_fn = fn.encode('cp437').decode('utf-8')  # 将文件名正确编码
            right_fn = os.path.join(release_file_dir, right_fn)

            if right_fn[-1] == '/':
                os.makedirs(right_fn, mode=0o777) #创建文件夹
                continue

            with codecs.open(right_fn, 'w+', encoding='utf-8') as output_file:  # 创建并打开新文件
                with zf.open(fn, 'r') as origin_file:  # 打开原文件
                    shutil.copyfileobj(origin_file, output_file)  # 将原文件内容复制到新文件

        renameFile(release_file_dir,new_dir)

        return os.path.join(release_file_dir,new_dir_name)```
3034 次点击
所在节点    Python
36 条回复
golmic
2018-06-26 12:42:25 +08:00
服务器的 python 版本是? Python 解压用的哪个库?我没理解错需求吧,就是程序解压 zip 的时候出的错
watermelon92
2018-06-26 12:48:59 +08:00
@golmic python3.4 解压用的 zipfile
1130335361
2018-06-26 12:55:46 +08:00
用的是 apache 还是 nginx,我之前 django 配合 apache 的时候出现过这个问题
watermelon92
2018-06-26 12:57:44 +08:00
@1130335361 用的 Nginx 加 gunicorn,你之前也是到服务器上才报错吗?
golmic
2018-06-26 13:02:00 +08:00
服务器上手动跑一下解压的函数,贴一下报错信息
1130335361
2018-06-26 13:10:14 +08:00
@watermelon92 是的,改了 apache 的的环境变量才行的
1130335361
2018-06-26 13:14:47 +08:00
1130335361
2018-06-26 13:16:19 +08:00
@watermelon92 拉到最底部有说“ Fixing UnicodeEncodeError for file uploads ”这个错误的解决办法,https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/uwsgi/
watermelon92
2018-06-26 13:33:35 +08:00
@golmic 好的,我稍后试下。谢谢!
watermelon92
2018-06-26 13:34:05 +08:00
@1130335361 我用的是 gunicorn,好像没写过 uwsgi.ini 文件。。
v1v
2018-06-26 13:47:46 +08:00
以前 centos 也出现这个问题, 改 /etc/sysconfig/i18n,
设置 LANG=en_US.UTF-8 , 重启服务器就好了
watermelon92
2018-06-26 13:57:44 +08:00
em...我的 ubuntu 系统没有 sysconfig 文件夹
watermelon92
2018-06-26 14:03:29 +08:00
@v1v 这是现在 locale 的结果:

LANG=en_US.utf8
LANGUAGE=
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=
freakxx
2018-06-26 14:20:11 +08:00
@watermelon92
直接去到 21 行 log 下看名字变成了什么;

确定编码问题后再往上处理

楼上说的解决办法
如果是 uwsgi + nginx 这一套,直接再 uwsgi 指定 LANG 就可以了。
lxy42
2018-06-26 14:24:21 +08:00
right_fn = fn.encode('cp437').decode('utf-8') # 将文件名正确编码
这里为什么需要对 fn 进行 encode 和 decode ? fn 如果可以 encode 的话,说明 fn 是 unicode 类型,就没必要先 encode 在 decode 了(最终结果还是 unicode ) 而且 encode 和 decode 的编码参数都不一致,可能会导致异常。

说回你的问题,我猜测是 `right_fn = os.path.join(release_file_dir, right_fn)` 导致`right_fn`编码出问题了,建议你检查一下`release_file_dir` 和 `right_fn ` 的编码。
watermelon92
2018-06-26 14:29:42 +08:00
debug 信息里,文件名是对的。因为 zipfile 解压是默认用‘ cp437 ’ decode 的,所以我先做了解压文件的名称处理。得到正确的文件名后,用 open()函数基于解压后的文件名创建文件的。目前就是提示在这个 open()函数上出错了。但我在服务器端直接运行同样的函数是可以正常创建文件的。
watermelon92
2018-06-26 14:32:03 +08:00
@lxy42
@freakxx
两位大佬我在楼上回复了
watermelon92
2018-06-26 14:39:07 +08:00
@lxy42
@freakxx
我把 debug 出来的文件名称截图了,见下方链接:
http://7xuagw.com1.z0.glb.clouddn.com/debug.png
glasslion
2018-06-26 15:05:47 +08:00
@watermelon92
目前你的写法是要求 zip 包里的所有文件都是 utf-8 编码的。
既然你目的是复制文件,直接把文件以二进制打开,岂不是更简单?
freakxx
2018-06-26 15:12:37 +08:00
$LANG

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/465935

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX