Reputation: 35
I'm creating a file server by flask. When I'm testing the download feature, I found it raises UnicodeEncodeError if I try to download files named with UTF-8 characters.
Create a file at upload/1512026299/%E6%97%A0%E6%A0%87%E9%A2%98.png
, then run codes below:
@app.route('/getfile/<timestamp>/<filename>')
def download(timestamp, filename):
dirpath = os.path.join(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'upload'), timestamp)
return send_from_directory(dirpath, filename, as_attachment=True)
You will get an exception, which should be like this:
127.0.0.1 - - [30/Nov/2017 21:39:05] "GET /getfile/1512026299/%E6%97%A0%E6%A0%87%E9%A2%98.png HTTP/1.1" 200 -
Error on request:
Traceback (most recent call last):
File "C:\Program Files\Python36\lib\site-packages\werkzeug\serving.py", line 209, in run_wsgi
execute(self.server.app)
File "C:\Program Files\Python36\lib\site-packages\werkzeug\serving.py", line 200, in execute
write(data)
File "C:\Program Files\Python36\lib\site-packages\werkzeug\serving.py", line 168, in write
self.send_header(key, value)
File "C:\Program Files\Python36\lib\http\server.py", line 508, in send_header
("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 43-45: ordinal not in range(256)
Upvotes: 2
Views: 2926
Reputation: 69022
The problem is that when using as_attachement=True
the filename is sent in the headers. Unfortunately it seems that flask does not yet support rfc5987 which specifies how to encode attachment file names in a different encoding other than latin1.
The easiest solution in this case would be to drop as_attachement=True
, then it won't be sent with a Content-Disposition
header, which avoids this problem.
If you really have to send the Content-Disposition
header you could try the code posted in the related issue:
response = make_response(send_file(out_file))
basename = os.path.basename(out_file)
response.headers["Content-Disposition"] = \
"attachment;" \
"filename*=UTF-8''{utf_filename}".format(
utf_filename=quote(basename.encode('utf-8'))
)
return response
This should be fixed in the next release (>0.12)
Upvotes: 7