Django REST Framework文件接口格式校验:CSV/Excel上传报错排查
这个问题我之前碰到过,大概率是文件MIME类型的检测逻辑不够全面导致的——尤其是CSV文件,很多浏览器会把它识别为text/plain,而不是标准的text/csv,这就会触发你的类型验证错误。结合你的需求,我给你一套完整的解决方案:
问题定位
你看到的Wrong file type: text/plain错误,说明你的序列化器(serializer)里的文件类型验证逻辑,只允许了CSV文件的标准MIME类型text/csv,但忽略了浏览器可能发送的text/plain类型;同时可能没有结合文件扩展名做双重验证,导致判断不够准确。
解决方案
1. 完善序列化器的文件验证逻辑
在serializers.py里自定义验证方法,同时检查文件扩展名和真实MIME类型,这样既兼容浏览器的类型识别差异,又能防止伪造扩展名的恶意文件:
from rest_framework import serializers from .models import File import magic # 需要安装依赖:pip install python-magic(Windows用pip install python-magic-bin) class FileSerializer(serializers.ModelSerializer): class Meta: model = File fields = ['file', 'remark', 'timestamp'] def validate_file(self, value): # 允许的文件扩展名 allowed_extensions = ['csv', 'xls', 'xlsx'] # 允许的MIME类型(包含CSV可能的text/plain) allowed_mime_types = [ 'text/csv', 'text/plain', # 兼容浏览器识别CSV为纯文本的情况 'application/vnd.ms-excel', # XLS格式 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' # XLSX格式 ] # 第一步:检查文件扩展名 file_ext = value.name.split('.')[-1].lower() if file_ext not in allowed_extensions: raise serializers.ValidationError(f"不支持的文件格式:{file_ext},仅接受CSV、XLS、XLSX") # 第二步:检查文件真实MIME类型(避免伪造扩展名) mime_type = magic.from_buffer(value.read(1024), mime=True) value.seek(0) # 重置文件指针,避免后续读取出错 if mime_type not in allowed_mime_types: raise serializers.ValidationError(f"错误的文件类型:{mime_type}") return value
如果不想依赖python-magic,可以只做扩展名验证(安全性稍弱,但满足大多数场景):
def validate_file(self, value): allowed_extensions = ['csv', 'xls', 'xlsx'] file_ext = value.name.split('.')[-1].lower() if file_ext not in allowed_extensions: raise serializers.ValidationError(f"不支持的文件格式:{file_ext},仅接受CSV、XLS、XLSX") return value
2. 确保API强制返回JSON响应
在视图层配置render_classes,强制接口返回JSON格式,同时配置文件上传所需的解析器:
from rest_framework import generics, status from rest_framework.response import Response from rest_framework.renderers import JSONRenderer from rest_framework.parsers import MultiPartParser, FormParser from .serializers import FileSerializer from .models import File class FileUploadAPIView(generics.CreateAPIView): queryset = File.objects.all() serializer_class = FileSerializer renderer_classes = [JSONRenderer] # 强制返回JSON格式 parser_classes = [MultiPartParser, FormParser] # 处理文件上传请求 def create(self, request, *args, **kwargs): # 调用父类方法完成文件保存 response = super().create(request, *args, **kwargs) # 自定义JSON响应内容 return Response({ 'code': 201, 'message': '文件上传成功', 'data': { 'file_id': response.data['id'], 'file_name': response.data['file'], 'remark': response.data['remark'] } }, status=status.HTTP_201_CREATED)
3. 测试验证
上传CSV文件时,即使浏览器发送text/plain的MIME类型,也会因为我们把它加入了允许列表,同时扩展名是.csv,所以能通过验证;Excel文件的MIME类型和扩展名也都被覆盖,不会再出现类型错误。
内容的提问来源于stack exchange,提问作者Majid199372
相关产品推荐
相关产品推荐

