Django对接React上传图片触发utf-8解码错误如何排查修复
错误根因
这个UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0报错的核心是:0xff是JPEG等常见二进制图片格式的文件头字节,Django侧没有将请求识别为文件上传请求,把二进制图片内容当成UTF-8编码的文本尝试解码,最终触发报错。
具体问题点分三部分:
- 后端序列化器继承错误:当前
ImgSerializer继承的是基础serializers.Serializer,其内部定义的Meta类完全不生效,DRF会将上传的文件字段按普通文本字段做校验,触发解码逻辑。 - 前后端字段不匹配+视图逻辑错误:模型中图片字段名为
image,后端取文件、前端传参的字段名都用的img,字段映射关系断裂;同时视图类定义缺少冒号、未按ModelViewSet要求声明queryset和serializer_class,本身就无法正常运行。 - 前端请求配置错误:
useState初始值设为空字符串,后续却按对象结构做展开赋值,存在逻辑隐患- 依赖axios发异步请求时,默认会带上
Content-Type: application/json请求头,没有配置multipart/form-data头,Django不会走文件上传解析逻辑;而form标签上的encType属性只对原生表单提交生效,对ajax请求完全无效 - 存入状态的文件被包裹在对象结构中,append到FormData时传入的是整个JS对象而非File实例,数据格式不符合要求
修复方案
按前后端分别修正代码即可解决:
后端(Django)修正
- 修复序列化器,继承模型序列化器,自动映射模型字段:
# serializer.py from rest_framework import serializers from . import models class ImgSerializer(serializers.ModelSerializer): class Meta: model = models.ImageModel fields = '__all__'
- 修复视图逻辑,补全ModelViewSet必要配置,统一字段名,复用序列化器的保存逻辑:
# views.py from rest_framework import viewsets, status from rest_framework.response import Response from . import models, serializer class ImgView(viewsets.ModelViewSet): queryset = models.ImageModel.objects.all() serializer_class = serializer.ImgSerializer def create(self, request, *args, **kwargs): ser = self.get_serializer(data=request.data) if ser.is_valid(): ser.save() return Response("Success", status=status.HTTP_201_CREATED) return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)
- 确认基础配置正确:
settings.py中已注册rest_framework应用- 已配置
MEDIA_URL、MEDIA_ROOT参数,保证文件能正常存储 - 开发环境下在
urls.py中配置了媒体文件路由,可正常访问上传后的资源
前端(React)修正
修正状态逻辑、请求配置,统一字段名,保证上传的是标准FormData格式文件:
import { useState } from 'react' import axios from 'axios' function ComponentImage(){ // 初始值直接设为null,单独存储选中的文件实例 const [img, setImg] = useState(null) const handleFileChange = (e) => { setImg(e.target.files[0]) } const submitChange = async (e) => { e.preventDefault() if (!img) return const formData = new FormData() // 字段名和后端模型字段对齐为image formData.append('image', img) await axios.post('http://127.0.0.1:8000/', formData, { headers: { // 关键:指定multipart类型,不要手动设置boundary,由浏览器自动生成 'Content-Type': 'multipart/form-data' } }) } return( <div> <form onSubmit={submitChange}> <div className='divlbl'> <label htmlFor="upload" className='imglbl'>Upload An Image</label> </div> <input id='upload' required type='file' name='image' accept="image/*" onChange={handleFileChange} /> <button type="submit">上传</button> </form> </div> ) }
修复完成后重新发起请求,Django可正确识别文件上传请求,从request.FILES中拿到二进制文件实例,不会再触发UTF-8解码错误。
内容的提问来源于stack exchange,提问作者Ghazi
相关产品推荐
相关产品推荐

