[求大神解答] 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)```
3067 次点击
所在节点    Python
36 条回复
freakxx
2018-06-26 15:14:22 +08:00
@watermelon92
echo $LANG
然后在 Gunicorn 指定用户为你当前用户
试下
lxy42
2018-06-26 15:19:12 +08:00
@watermelon92 #18
right_fn 编码没问题,那可能是文件系统编码默认是 ascii 的问题,你看一下 sys.getfilesystemencoding()是什么。
如果是 ascii 的话,
1. 设置正确的 locale
或者
2. 将 right_fn 编码为 bytes:
right_fn = right_fn.encode(ENCODING)
with codecs.open(right_fn, 'w+', encoding='utf-8') as output_file: # 创建并打开新文件
Tzen
2018-06-26 15:20:23 +08:00
之前遇到过这个问题,我用 supervisor 管理的进程,配置里更改环境变量就好;
我项目里是这么加的:environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8
copie
2018-06-26 15:39:19 +08:00
这个属于系统编码的问题。我用 docker 发布的时候如下解决的。


echo "zh_CN.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
ENV LANG=zh_CN.UTF-8
copie
2018-06-26 15:39:57 +08:00
这个属于系统编码的问题。我用 docker 发布的时候如下解决的。

RUN echo "zh_CN.UTF-8 UTF-8" > /etc/locale.gen
RUN locale-gen
ENV LANG=zh_CN.UTF-8
robinlovemaggie
2018-06-26 15:46:04 +08:00
把字符乱码问题归结系统语言设置上是不可取的,这本身不符合 KISS 原则的。
问题可能处在你的开发环境里“ cp437 ”字符编码不能和目标服务器兼容,处理这部分就好了,放弃修改服务器系统设置。
freakxx
2018-06-26 15:55:24 +08:00
@watermelon92
@copie


尽量像
@robinlovemaggie
说的,
不要去动系统层面的配置

如果是用 uwsgi 那么就在里面指定 LANG
如果是用 supervisor 也在里面像 @Tzen 说的,设置下
robinlovemaggie
2018-06-26 16:02:36 +08:00
@freakxx 附议。
@watermelon92 其实道理很简单,如果是靠更改系统设置解决了问题,那么换一个系统,问题依然存在,等于问题没解决。
watermelon92
2018-06-26 16:26:50 +08:00
@robinlovemaggie
@freakxx
谢谢指导。
cp437 是 zipfile 的标准吧?为啥会不兼容 ubuntu ?而且我打印出来的 log 是显示正常的,楼上有截图。
robinlovemaggie
2018-06-26 16:35:03 +08:00
@watermelon92 来自 wiki 关于 codepage437 的解释:
Code page 437 is the character set of the original IBM PC (personal computer), or MS-DOS. It is also known as CP437, OEM 437, PC-8, or MS-DOS Latin US. The set includes ASCII codes 32 – 126, extended codes for accented letters (diacritics), some Greek letters, icons, and line-drawing symbols.
copie
2018-06-26 19:50:12 +08:00
@robinlovemaggie 但是通过配置 Python 启动的环境变量确实可以成功运行。但是如果有一天代码上线后出现问题远程打开代码注释都是乱码。log 汉字这是乱码岂不是更加的闹心。
tlday
2018-06-27 00:11:42 +08:00
呃,我没看懂你们在说啥,但是,同样是 zip 文件,在 Windows 下和 Unix 下,文件名的编码是有差异的,这个是 zip 文件标准没有覆盖文件名编码方式的问题,应该从这个方向着手。修改系统编码方式是不可取的。
tlday
2018-06-27 00:18:02 +08:00
你的注释打开原文件的这一行好像也没有指定打开文件的编码方式,然后把原文件复制到新文件如果编码不同,是可以直接复制的吗…不需要 decode,encode 吗?我在 python 解决编码问题方面是个菜鸡,只是提供下思路。
tlday
2018-06-27 00:29:29 +08:00
感觉自己没仔细看回复闹了乌龙
robinlovemaggie
2018-06-27 09:40:51 +08:00
@copie 远程汉字乱码可以改一下 ssh 工具的传输编码就行了
watermelon92
2018-06-27 12:22:17 +08:00
@golmic
我在服务器上单独运行了,成功解压没有报错。
demo 代码见下:
import os,shutil
import zipfile

filePath = '/Users/dylan/Desktop/3.2.zip'
release_file_dir = '/Users/dylan/Desktop/testunzip3'


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 open(right_fn, 'wb') as output_file: # 创建并打开新文件
with zf.open(fn, 'r') as origin_file: # 打开原文件
shutil.copyfileobj(origin_file, output_file) # 将原文件内容复制到新文件

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

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

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

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

© 2021 V2EX