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



我正在尝试设置Content-Disposition标头以将文件发送到客户端。文件名为 Unicode。当我尝试设置标题时,它失败并显示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: %srn" % (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 第 4 节介绍如何指定用于标头值的编码而不是 ASCII。使用标头选项 filename*=UTF-8''... ,其中 ... 是 url 编码的名称。您还可以包括 filename 选项以提供 ASCII 回退。

Flask>= 1.0 支持使用 Unicode 文件名调用send_from_directorysend_file。您可以将send_from_directoryas_attachment=True和 Unicode 文件名一起使用。

from flask import send_from_directory
@app.route("/send-python-report")
def send_python_report():
    return send_from_directory("reports", "python_report.html", as_attachment=True)

为了安全起见,请确保使用send_from_directory而不是send_file,如果文件名是由用户输入提供的。

<小时 />

在 Flask 1.0 之前,您可以使用 Flask 使用的相同过程手动构造标头。

import unicodedata
from urllib.parse import quote
from flask import send_from_directory
@app.route('/send-python-report')
def send_python_report():
    filename = "python_report.html"
    rv = send_from_directory("reports", filename)
    try:
        filename.encode("ascii")
    except UnicodeEncodeError:
        simple = unicodedata.normalize("NFKD", filename)
        simple = simple.encode("ascii", "ignore").decode("ascii")
        # safe = RFC 5987 attr-char
        quoted = quote(filename, safe="!#$&+-.^_`|~")
        names = {"filename": simple, "filename*": f"UTF-8''{quoted}"}
    else:
        names = {"filename": filename}
    rv.headers.set("Content-Disposition", "attachment", **names)
    return rv
<小时 />

直到最近(2017 年之前(,浏览器才始终支持这一点。此页面包含一些有关浏览器支持的指标。值得注意的是,IE8 将忽略 UTF-8 选项,如果 UTF-8 选项位于 ASCII 选项之前,IE8 将完全失败。

最新更新