You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django文件下载UTF-8-SIG编码异常问题求助

解决Django文件下载的编码问题

我尝试开发一个API从服务器文件夹下载文件,但遇到了编码问题。日志文件是使用UTF-8-SIG编码生成的,在服务器端可以正常读取,但从客户端下载后编码出现错误,显示异常文本。以下是我的代码:

@login_required(redirect_field_name="next",login_url='login_form')
def downloadMachineLog(request):
   if(request.method == "GET"):
      fileName = request.GET.get('fileName')
      BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
      filePath = BASE_DIR+"\\reminder\\log\\"+fileName
      file_is_exists = exists(filePath)
      print(filePath)
      if(file_is_exists):
         with open(filePath,'r',encoding='utf-8-sig') as file:
            mime_type,_ = mimetypes.guess_type(filePath)
            response = HttpResponse(file,content_type = mime_type+"charset=utf-8-sig")
            response['Content-Disposition'] = "attachment; filename=%s" % fileName
         return response
      else:
         return HttpResponse("This log is not exists")
   else:
      return HttpResponse("Error")

问题分析与修正方案

1. 文本模式读取文件破坏原始字节流

你用'r'文本模式打开文件时,Python会自动去除UTF-8-SIG的BOM头,并将内容转换为字符串。直接将字符串传给HttpResponse会触发Django的二次编码,破坏原始的UTF-8-SIG结构。必须用二进制模式'rb'打开文件,保留完整的原始字节。

2. Content-Type格式错误

你拼接mime_type和charset的方式不符合HTTP规范,正确格式应为[mime类型]; charset=utf-8-sig,而非直接拼接成mime_typecharset=utf-8-sig,这会导致浏览器无法识别编码规则。

3. 文件名未编码(非ASCII文件名适配)

如果文件名包含中文、特殊字符等非ASCII内容,直接写入Content-Disposition会导致客户端显示乱码。需要对文件名进行URL编码,同时遵循RFC 5987标准设置文件名参数。

4. 路径拼接不规范

硬编码的\\路径分隔符不兼容跨平台,应使用os.path.join生成标准化路径,避免因操作系统差异导致的文件找不到问题。

修正后的代码

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
import os
import mimetypes
from urllib.parse import quote

@login_required(redirect_field_name="next", login_url='login_form')
def downloadMachineLog(request):
    if request.method == "GET":
        fileName = request.GET.get('fileName')
        if not fileName:
            return HttpResponse("Missing file name parameter")
            
        BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        # 用os.path.join生成跨平台兼容路径
        filePath = os.path.join(BASE_DIR, 'reminder', 'log', fileName)
        
        if os.path.exists(filePath):
            # 二进制模式打开,保留原始UTF-8-SIG字节
            with open(filePath, 'rb') as file:
                mime_type, _ = mimetypes.guess_type(filePath)
                # 处理mime_type为空的情况,默认设为文本类型
                mime_type = mime_type or 'text/plain'
                # 正确设置Content-Type格式
                response = HttpResponse(file, content_type=f"{mime_type}; charset=utf-8-sig")
                # 编码文件名,兼容非ASCII字符与各类浏览器
                encoded_filename = quote(fileName)
                response['Content-Disposition'] = f"attachment; filename*=UTF-8''{encoded_filename}; filename={encoded_filename}"
            return response
        else:
            return HttpResponse("This log does not exist")
    else:
        return HttpResponse("Error: Invalid request method")

修正说明

  • 二进制模式读取确保UTF-8-SIG的BOM头完整传输到客户端,保留原始编码结构。
  • 规范的Content-Type格式让浏览器正确识别文件编码。
  • 文件名编码解决了非ASCII文件名的客户端显示乱码问题。
  • 标准化路径拼接提升了代码的跨平台兼容性。
  • 增加了文件名参数为空的判断,提升接口鲁棒性。

内容的提问来源于stack exchange,提问作者williamdam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:05:13