我正在尝试设置 Content-Disposition
header 以将文件发送到客户端。文件名为 Unicode。当我尝试设置 header 时,它失败并显示 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: %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 选项之前,IE8 将完全失败。
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_header
和 OrderedDict
完全手动构造 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/