python3中用django下載文件,中文名亂碼怎么辦?


前段時間被某個前端小可愛鄙視了一下,說我博客都一年不更新了,我不服,明明還有倆月才到一年呢。不過說是這么說,還是要更新一下的。
以上都是借口,下面開始正文。
 
 
我公司的某個內部系統,用django做的,項目中不可避免地有下載文件的地方,以前偷懶,我都是用django自帶的方法,在項目的總urls.py中使用
 
urlpatterns += static(FILEPATH, document_root=FILEPATH)

 

這種方法解決。
 
但是這種方法有個極大的缺陷:測試環境寫着玩可以,正式環境肯定要把settings中的debug=True關掉的。而這種方法,在關掉debug之后,就不能用了。
 
於是我只好走傳統線路:設置header。
 
在urls.py中增加:
 
url(r"^download/$", views.download, name="download")

 

在頁面中:
 
<a href="{% url 'download' %}">下載</a>

 

在views.py中增加一個視圖函數:
 
def download(request):
    return build_download_response(FILE_PATH, "我愛可樂.docx")

 

(MTV模式的程咬金三板斧,沒毛病)
 
由於系統里面不止一個地方用到下載功能,所以,我把它寫成了一個通用的函數:
 
from django.http import FileResponse
 
def build_download_response(filepath, filename):
    """
    構建下載文件的文件頭
    :param filepath: 文件路徑
    :param filename: 文件名
    :return: FileResponse
    """
    absname = os.path.join(filepath, filename) if os.path.isdir(filepath) else filepath
 
    response = FileResponse(open(absname, "rb"))
    response["Content-Type"] = "application/octet-stream"
    response["Content-Disposition"] = "attachment; filename='%s'" % filename
    return response
 

 

參照網上的說法,這樣是沒問題的。藍鵝,它確實出了問題:當我點擊下載按鈕的時候,彈出的界面只有“下載”二字。
 
 
喵喵喵?我的文件呢?
我嘗試把文件下載下來看了一下,從大小來看,是沒有問題的。
 
 
我把名字改過來,可以正常打開,里面沒有丟東西——換句話說, 只是文件名出了問題
可是文件名能有毛的問題啊?你不能欺負我公司的人只會中文吧!
 
 
 
經過一番激烈地百度和扣人心弦地搜索,我從這篇博客  https://blog.csdn.net/u011090495/article/details/18815777 里找到了原因。
簡單點說就是, Content-Disposition里面的filename這個東西,原來不是RFC標准,僅支持ASCII編碼的文件名。如果文件名不是英文的,恐怕就會出現名字亂碼,或者被改名的情況那么怎么辦呢?另一個RFC給加上了擴展,可以定義一個filename*,然后把文件名編碼一下。
於是,我把 Content-Disposition 這里從
 
response["Content-Disposition"] = "attachment; filename='%s'" % filename

 

改成了
 
response["Content-Disposition"] = "attachment; filename='%s'; filename*=UTF-8''%s" % (filename.encode("UTF-8"), filename.encode("UTF-8"))

 

結果測試了一下,哭了。
 
 
還真是編碼了……
我要鬧了。
 
還好,后來又在  https://segmentfault.com/q/1010000009078463 這篇帖子里找到了答案。原來 filename*=UTF-8''%s" % filename.encode("UTF-8") 這樣寫是不管用的,django自有django的方法:
 
from django.http import FileResponse
from django.utils.encoding import escape_uri_path
 
def build_download_response(filepath, filename):
    """
    構建下載文件的文件頭
    :param filepath: 文件路徑
    :param filename: 文件名
    :return: FileResponse
    """
    absname = os.path.join(filepath, filename) if os.path.isdir(filepath) else filepath
 
    response = FileResponse(open(absname, "rb"))
    response["Content-Type"] = "application/octet-stream"
    response["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(escape_uri_path(filename)) return response
 

 

於是,就可以正常下載了。
 
 
 
打開看看,內容完全沒問題!
 
 
 
開心!(我才不會拿去給前端炫耀呢!)
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM