Django-React框架图片上传返回403错误求助
问题分析与解决
1. 装饰器顺序错误导致@csrf_exempt失效
你当前将@api_view(['POST'])放在@csrf_exempt上方,DRF的api_view装饰器会优先处理请求,内部默认启用CSRF校验,导致@csrf_exempt无法生效。正确的装饰器顺序需将@csrf_exempt放在@api_view之前:
@csrf_exempt @api_view(['POST']) def upload_images(request, format=None): # 你的视图逻辑
不过更推荐的方式是保留CSRF校验,在React请求中正确携带Token,安全性更高。
2. React端正确携带CSRF Token的方法
Django会在用户访问页面时设置csrftoken Cookie,你可以在React中读取该Cookie,然后在上传请求的请求头中添加X-CSRFToken字段:
示例代码(React):
// 可使用js-cookie库简化Cookie读取,或自行实现读取逻辑 import Cookies from 'js-cookie'; const uploadImages = async (formData) => { const csrfToken = Cookies.get('csrftoken'); try { const response = await fetch('/upload/', { method: 'POST', headers: { 'X-CSRFToken': csrfToken, // 注意:上传文件时不要手动设置Content-Type,浏览器会自动处理multipart/form-data格式 }, body: formData, }); // 处理响应逻辑 } catch (error) { console.error(error); } };
若不想依赖第三方库,可自行编写Cookie读取函数:
function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
3. 视图逻辑中的其他潜在错误
除CSRF问题外,你的视图还有两处需修正:
- 模型字段为
image_url,但你在Image.objects.create(image=images)中使用了不存在的image字段,需改为Image.objects.create(image_url=images)。 - 你已通过
serializer.save()创建实例,后续重复调用Image.objects.create会生成重复记录,需删除其中一处。
修正后的视图代码:
# 若采用React携带Token的方式,可移除@csrf_exempt装饰器 @csrf_exempt @api_view(['POST']) def upload_images(request, format=None): if request.method == 'POST': # 注意:many=True适用于批量上传,若前端仅传单个文件需移除该参数 serializer = ImageSerializer(data=request.data, many=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
后台手动上传正常的原因
Django Admin内部已自动处理CSRF Token的携带逻辑,因此从Admin面板上传不会触发CSRF错误。
内容的提问来源于stack exchange,提问作者Jorge Rodríguez Peña
相关产品推荐
相关产品推荐

