Django 實現下載功能時中文文件名問題


 

先上最終解決代碼(有待驗證各瀏覽器效果):

def download_file(request, file_path):
    file_name = os.path.basename(file_path)
    if not os.path.isfile(file_path):
        return HttpResponse(file_name)

    def file_iterator(tar_file_path, chunk_size=512):
        with open(tar_file_path, mode='rb') as file:
            while True:
                content = file.read(chunk_size)
                if content:
                    yield content
                else:
                    break

    try:
        response = StreamingHttpResponse(file_iterator(file_path))
        response['Content-Type'] = 'application/octet-stream'response["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(escape_uri_path(file_name)) except:
        return HttpResponse("Sorry but Not Found the File")

    return response

 

重點在於黃色記號筆標注的那行代碼。
網上大多資料都是這么寫的:

response['Content-Disposition'] = 'attachment;filename="{}"'.format(file_name)

 

這種寫法對應純英文的文件名是沒有問題的,因為 Content-Disposition 里面的 filename ,不是RFC標准,僅支持ASCII編碼的文件名。如果文件名不是英文的,就會出現名字亂碼,或者被改名的情況。

 

如何直接采用解碼的方式也還是會出現byte數組的文件名:

response['Content-Disposition'] = 'attachment;filename="{}"'.format(file_name.encode('utf8'))

得到的結果類似於這樣:b'-xc6-xbd-xcc-xa8-xc4-xda-xb2-xbf-xb2-xe2-xca-xd4.xlsx' (3).xls

 

原因是不同瀏覽器對於下載文件文件名的編碼解析格式不一樣,常用瀏覽器解析格式如下:

  • IE瀏覽器,采用URLEncoder編碼
  • Opera瀏覽器,采用filename*方式
  • Safari瀏覽器,采用ISO編碼的中文輸出
  • Chrome瀏覽器,采用Base64編碼或ISO編碼的中文輸出
  • FireFox瀏覽器,采用Base64或filename*或ISO編碼的中文輸出

 

如果硬來的話就是在后台把文件名先 encode 成 bytes,再判斷瀏覽器,根據不同的瀏覽器用相應的編碼decode一下就好了
例如瀏覽器是FireFox,后台編碼是 utf-8,則進行如下操作

response['Content-Disposition'] = 'attachment; filename=' + filename.encode('utf-8).decode('ISO-8859-1')

 


免責聲明!

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



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