Flask文件下载中文文件名处理解决方案
问题背景
在Web应用开发中,当用户下载包含中文字符的文件时,经常会遇到文件名乱码或无法正确显示的问题。这是由于HTTP协议中的 Content-Disposition 头部字段对非ASCII字符的处理限制导致的。
问题分析
核心问题
- 编码问题 :HTTP头部字段默认使用ASCII编码,无法直接支持中文等Unicode字符
- 浏览器兼容性 :不同浏览器对非ASCII文件名的处理方式不同
- RFC标准 :需要遵循RFC 6266标准来正确处理国际化文件名
常见症状
- 下载的文件名显示为乱码
- 中文文件名变成问号或其他符号
- 部分浏览器无法正确解析文件名
解决方案
技术实现
在Flask应用中,我们采用了双重编码策略来确保中文文件名的正确处理:
from urllib.parse import quote
from flask import send_file
# 设置文件名,支持中文文件名
file_name = quote(download_name)
response.headers['Content-Disposition'] = f'attachment; filename="{file_name}"; filename*=utf-8\'\'\'{file_name}'
关键技术点
- URL编码处理
file_name = quote(download_name)
- 使用 urllib.parse.quote() 对文件名进行URL编码
- 将中文字符转换为百分号编码格式(如: %E4%B8%AD%E6%96%87 )
- 双重文件名策略
response.headers['Content-Disposition'] = f'attachment; filename="{file_name}";
filename*=utf-8\'\'\'{file_name}'
参数说明:
- filename=“{file_name}” :为旧版浏览器提供ASCII兼容的文件名
- filename*=utf-8’‘’{file_name} :符合RFC 6266标准的国际化文件名 3. RFC 6266标准格式
filename*=charset'language'encoded-filename
- charset :字符集(utf-8)
- language :语言标识(空字符串表示未指定)
- encoded-filename :URL编码后的文件名
完整实现示例
class TaskDownloadAPI(Resource):
def get(self, task_id):
"""下载翻译后的文件"""
try:
# ... 其他业务逻辑 ...
# 获取原始文件名
download_name = task_info.get('original_filename')
if not download_name:
file_ext = os.path.splitext(output_file)[1]
download_name = f"translated_{task_id}{file_ext}"
# 创建响应
response = send_file(
output_file,
as_attachment=True
)
# 设置文件名,支持中文文件名
file_name = quote(download_name)
response.headers['Content-Disposition'] = f'attachment; filename="{file_name}"; filename*=utf-8\'\'\'{file_name}'
return response
except Exception as e:
logger.error(f"文件下载异常 - 任务ID: {task_id}, 错误: {str(e)}")
return {'error': f'下载文件时发生错误: {str(e)}'}, 500