flask+gunicorn中文文件下載報錯問題及解決

導言

問題源起與一個靜態文件下載的接口:

from flask import Flask, current_app
app = Flask(__name__)

@app.route('/file_name')
def file_download(file_name):
    return send_from_directory(current_app.root_path, file_name)

當file_name中有中文的時候出現內部錯誤提示:

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 46-47: ordinal not in range(256)

故障排解

查找發現發現是中文編碼出了問題,需要對響應頭進行設置: 參考

from flask import Flask, current_app,send_from_directory
app = Flask(__name__)


@app.route('/file_name')
def file_download(file_name):
    res = make_response(send_from_directory(current_app.root_path, file_name, as_attachment=True, conditional=True))
    res.headers["Content-Disposition"] = 'attachment; filename*="utf-8\'\'{}"'.format(file_name.encode().decode('latin-1'))
    return res

這下在本地運行終於可以正常下載了。但放到服務器上用gunicorn部署的時候又出現了問題:

Traceback (most recent call last):
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/workers/sync.py", line 135, in handle
    self.handle_request(listener, req, client, addr)
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/workers/sync.py", line 179, in handle_request
    resp.write_file(respiter)
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/http/wsgi.py", line 411, in write_file
    if not self.sendfile(respiter):
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/http/wsgi.py", line 390, in sendfile
    self.send_headers()
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/http/wsgi.py", line 337, in send_headers
    util.write(self.sock, util.to_bytestring(header_str, "ascii"))
  File "/home/dev/backend/backcode/convert-excel/venv/lib/python3.5/site-packages/gunicorn/util.py", line 509, in to_bytestring
    return value.encode(encoding)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 152-157: ordinal not in range(128)

經過一番查找,又找到了這個網址,參考裏面的回答,又將代碼改成下面這種形式:

from urllib.parse import quote

from flask import Flask, current_app,send_from_directory

app = Flask(__name__)

@app.route('/file_name')
def file_download(file_name):
    res = make_response(send_from_directory(current_app.root_path, file_name, as_attachment=True, conditional=True))
    res.headers["Content-Disposition"] = 'attachment; filename={}"'.format(quote(file_name))
    return res

這下終於成功下載中文文件名的文件了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章