
我最近在处理一个用Flask框架做的文件上传功能的时候遇到了问题。当时用户上传了一个名字叫做“产品图片.jpg”的图片文件, 结果传到服务器那边保存的时候, 发现文件名变成了空的, 然后程序就报错停止运行了。经过一番排查, 我发现问题出在老熟人那个坑上。第一个坑是这个空白区域会直接把中文给吞掉。使用Flask来进行文件上传的操作时, 官方的示例文档中大多数的情况下都会采用以下的这种书写方式来呈现。from werkzeug.utils import secure_filenamefilename secure_filename(产品图片.jpg)print(filename) # 输出.jpg ← 文件名没了这个方案的初衷是为了把那些具有危险倾向的内容给剔除掉, 不过它在判断什么是有害内容的时候, 把标准定得有点过于宽泛了, 只要不是那些基础的英文ASCII编码范围内的符号, 全都算作是不合规的, 所以中文文字在这种机制下面就被直接丢弃掉了。假若文件名全部都是由汉字构成的, 那么所返回的内容就是一个空荡荡的、名为点 jpg 的东西, 在随后的 open() 操作执行期间会直接引发错误报告。这是一个坑, 关于os.path在相关的编码上面存在一些问题的。在那个运行环境当中, 假如说脚本所使用的编码方式和那个操作系统当前的编码方式并不相同, 那么就可能出现这样的情况, 就是通过那些类似os.path.开头的函数, 还有那种以os.为开头的各种操作手段去处理带有中文字符的路径信息的时候, 系统很有可能会报错, 把错误给扔出来。UnicodeEncodeError: gbk codec cant encode character...具体的解决办法就是要在脚本的头部把编码给声明清楚, 而且还要一致地使用.Path来替代os.path这个方法。# -*- coding: utf-8 -*-from pathlib import Pathp Path(D:/上传文件/产品图片.jpg)print(p.exists()) # 正常工作第三个坑在于, 在使用open()函数来执行写文件操作时, 其默认采用的编码格式并不是UTF-8。# 危险写法Windows 下默认 GBKwith open(结果.txt, w) as f:f.write(中文内容)# 安全写法with open(结果.txt, w, encodingutf-8) as f:f.write(中文内容)要努力培养好的编程习惯, 就是在进行任何中文内容的文件读取和写入操作的时候, 都必须明确地为参数写上等于符号并紧跟引号包裹的utf-8这个编码值。对函数e()进行了解决。针对第一个存在问题的点, 开发者可以自行编写一个函数来替代原有的()符号处理逻辑。在这个过程中, 需要确保中文内容得以保留的同时, 将那些具有真实危险性的特殊字符进行过滤操作。import reimport uuiddef safe_chinese_filename(filename: str) - str:安全处理文件名支持中文。- 保留中文、英文、数字、点、下划线、连字符- 过滤路径穿越字符/ \\ .. 等- 文件名为空时自动生成 UUID 文件名# 分离文件名和扩展名if . in filename:name, ext filename.rsplit(., 1)ext . re.sub(r[^\w], , ext) # 扩展名只保留字母数字else:name, ext filename, # 只保留中文、字母、数字、下划线、连字符name re.sub(r[^\w\u4e00-\u9fff\-], _, name)name name.strip(_)# 如果处理后为空用 UUID 兜底if not name:name uuid.uuid4().hex[:8]return name ext# 测试print(safe_chinese_filename(产品图片.jpg)) # 产品图片.jpgprint(safe_chinese_filename(../../../etc/passwd)) # ______etc_passwdprint(safe_chinese_filename(.jpg)) # a1b2c3d4.jpgUUID兜底print(safe_chinese_filename(hello world.png)) # hello_world.pngFlask 中替换使用# 原来filename secure_filename(file.filename)# 替换为filename safe_chinese_filename(file.filename)小结问题原因解决方案在上传中文文件名之后, 该文件就会从可见状态中消失不见。()过滤非 ASCII使用自定义e()在处理中文路径的时候, 出现了编码错误的状况。GBK 与 UTF-8 不一致改用.Path把中文内容写成文件的时候, 会出现乱码的情况。打开这个方法。默认使用的编码格式并不是 UTF-8 这种。显式声明utf-8在这三个坑里头, 我全部都发生在同一个项目的范畴之内进行过亲身尝试与经历, 现在把这些问题进行梳理和汇总整理出来的目的, 主要是期望能够帮助到你, 让你在未来的工作开展当中少去走一些原本可能出现的弯曲的路途。如果你目前也在利用 Flask 这个框架来进行关于文件上传方面的一些操作和处理的话, 对于 e() 这个函数, 你完全可以直接将代码拿过来使用就可以了无需进行额外的调整或者修改。