我正在尝试设置Content-Disposition
标头以将文件发送到客户端。文件名为 Unicode。当我尝试设置标题时,它失败并显示UnicodeEncodeError
.我尝试了encode
和decode
的各种组合,但无法使其正常工作。如何发送带有 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_directory
和send_file
。您可以将send_from_directory
与as_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 将完全失败。