Python3.x在django中如何设置Content-Disposition,才能让浏览器正确保存中文命名的文件?

我在用Python 3.5 开发Django应用,其中有一个view是负责生成excel表格并提供给用户下载,大致代码如下:

from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_workbook


def example(request):
    wb = Workbook(write_only=True)
    excel_data = [['a', 'b', 'c']]
    ws = wb.create_sheet()
    for line in excel_data:
        ws.append(line)
    response = HttpResponse(save_virtual_workbook(wb), content_type='application/octet-stream')
    response['Content-Disposition'] = 'attachment; filename=somefile.xls'
    return response

其中用英文的文件名如animal.xls,浏览器显示正常,但是用了中文后,就是默认的文件名,如下载.xls,或者如果我用了utf-8编码,是乱码b'-xc6-xbd-xcc-xa8-xc4-xda-xb2-xbf-xb2-xe2-xca-xd4.xlsx' (3).xls,不知道如何解决。

阅读 11.3k
2 个回答

在网上找到了解决方案,使用下面的代码,文件名成功显示了中文。

from django.utils.encoding import escape_uri_path
from django.http import HttpResponse
def test(request):
    file_name = '测试.txt'
    content = ...
    response = HttpResponse(content, content_type='application/octet-stream')
    response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(file_name))
    return response

注:我在Firefox和Chrome上测试过了,运行正确,别的浏览器就不清楚了。

原因是不同浏览器对于下载文件文件名的编码解析格式不一样

在后台把文件名先encode成bytes,再判断浏览器,根据不同的浏览器用相应的编码decode一下就好了
例如浏览器是ff,后台编码是utf-8
response['Content-Disposition'] = 'attachment; filename=' + filename.encode('utf-8).decode('ISO-8859-1')
就ok了

常用浏览器解析格式。

IE浏览器,采用URLEncoder编码
Opera浏览器,采用filename*方式
Safari浏览器,采用ISO编码的中文输出
Chrome浏览器,采用Base64编码或ISO编码的中文输出
FireFox浏览器,采用Base64或filename*或ISO编码的中文输出
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏