python - 在 Flask 响应头中设置 Unicode 文件名

标签 python python-3.x flask http-headers

我正在尝试设置 Content-Disposition header 以将文件发送到客户端。文件名为 Unicode。当我尝试设置 header 时,它失败并显示 UnicodeEncodeError。我尝试了 encodedecode 的各种组合,但无法正常工作。如何发送具有 Unicode 文件名的文件?

destination_file = 'python_report.html'
response.headers['Content-Disposition'] = 'attachment; filename=' + destination_file
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/server.py", line 495, in send_header
    ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 41-42: ordinal not in range(256)

最佳答案

RFC 2231 section 4描述了如何指定一种编码来代替 Latin-1 用于 header 值。使用 header 选项 filename*=UTF-8''...,其中 ... 是 url 编码的名称。您还可以包含 filename 选项以提供 Latin-1 回退。

直到最近,浏览器才始终支持这一点。 This page有一些关于浏览器支持的指标。值得注意的是,IE8 将忽略 UTF-8 选项,如果 UTF-8 选项出现在 Latin-1 选项之前,I​​E8 将完全失败。

flask 1.0 supports calling send_file with Unicode filenames .如果你使用 Flask 1.0,你可以使用 send_file使用 as_attachment=True 和 Unicode 文件名。

from flask import send_file

@app.route('/send-python-report')
def send_python_report():
    return send_file('python_report.html', as_attachment=True)

在那之前,您可以使用 Flask 将使用的相同进程手动构造 header 。

import unicodedata

from flask import send_file
from werkzeug.urls import url_quote

@app.route('/send-python-report')
def send_python_report():
    filename = 'python_report.html'
    rv = send_file(filename)

    try:
        filename = filename.encode('latin-1')
    except UnicodeEncodeError:
        filenames = {
            'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
            'filename*': "UTF-8''{}".format(url_quote(filename)),
        }
    else:
        filenames = {'filename': filename}

    rv.headers.set('Content-Disposition', 'attachment', **filenames)
    return rv

为了安全起见,您应该使用 send_from_directory相反,如果文件名是由用户输入提供的。过程同上,代入函数。


WSGI 不保证 header 选项的顺序,所以如果你想支持 IE8,你必须使用 dump_options_headerOrderedDict 完全手动构造 header 值。否则,filename* 可能会出现在 filename 之前,如上所述,这在 IE8 中不起作用。

from collections import OrderedDict
import unicodedata

from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote

@app.route('/send-python-report')
def send_python_report():
    filename = 'python_report.html'
    rv = send_file(filename)
    filenames = OrderedDict()

    try:
        filename = filename.encode('latin-1')
    except UnicodeEncodeError:
        filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
        filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
    else:
        filenames['filename'] = filename

    rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
    return rv

关于python - 在 Flask 响应头中设置 Unicode 文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43365640/

相关文章:

python - 使用 Flask 保存并发送大型 numpy 数组

Python 正则表达式匹配鞋码

python - 如何将 "2019-11-30T07:00:00+09:00"日期转换为整数?

python - 如何在 PyQt4 中创建 QString?

python - 将列表中的空值替换为另一个列表中的值

python - 将 Flask 中的 URL 还原为端点 + 参数

python - 苹果操作系统 : unable to use virtualenv

python-3.x - 如何在Python中使用Gtk中的OpenCV画图

python - 具有独特字段的 Django UpdateView

python - 在 Flask 蓝图之间共享表单