使用POST请求上传Base64图片时遭遇403错误求助
问题分析与解决方案
核心问题:请求未携带有效认证凭证 + CSRF凭证未正确传递
1. 前端请求缺少认证Token
dj-rest-auth依赖JWT或Session认证,创建Post要求用户已完成认证,但你的fetch请求未携带任何认证信息:
- 若使用JWT认证,需在请求头添加
Authorization: Bearer <access_token>,token可从localStorage获取(登录时dj-rest-auth会返回该值); - 若使用Session认证,需给fetch设置
credentials: 'include',确保Cookie(含CSRF Token)能正常传递到后端。
修改前端fetch代码:
export async function action({ request }) { const data = await request.formData(); const postData = { title: data.get('title'), image: data.get('base64File'), }; // 从localStorage取登录后保存的access token(根据实际存储键名调整) const accessToken = localStorage.getItem('access_token'); // 从Cookie或localStorage获取CSRF Token const csrfToken = localStorage.getItem('csrftoken') || document.cookie.match(/csrftoken=([^;]+)/)[1]; const response = await fetch('http://127.0.0.1:8000/posts', { method: 'POST', credentials: 'include', // 发送Cookie,支持Session/CSRF验证 headers: { "Content-Type": "application/json", "Authorization": `Bearer ${accessToken}`, // JWT认证头 "X-CSRFToken": csrfToken // CSRF Token }, body: JSON.stringify(postData), }); // 后续代码保持不变 }
2. 自定义权限类可能在创建阶段误拦截
视图配置的IsCurrentUserOwnerOrReadOnly权限类需检查逻辑:
- 该类仅应在更新/删除操作时校验用户是否为Post的owner,创建操作时无需校验(因为
perform_create会自动将当前用户设为owner); - 若权限类在创建阶段就执行
request.user == obj.owner校验,此时Post对象尚未创建,owner字段为空,会直接返回403。
确保自定义权限类代码如下(仅在详情操作时校验owner):
from rest_framework import permissions class IsCurrentUserOwnerOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): # 所有只读请求直接放行 if request.method in permissions.SAFE_METHODS: return True # 仅允许Post的owner执行修改/删除操作 return obj.owner == request.user
注:has_object_permission仅在详情视图(如RetrieveUpdateDestroyAPIView)生效,ListCreateAPIView的create操作不会触发该方法,但如果权限类重写了has_permission,需确保create逻辑不被拦截。
3. 图片base64格式的后端适配(额外注意)
若Post模型的image字段是models.ImageField,直接传递base64字符串会导致序列化失败,可二选一做调整:
- 前端改用FormData传文件:无需转base64,直接传递原生文件对象,请求自动使用
multipart/form-data格式:
export async function action({ request }) { const formData = new FormData(); formData.append('title', request.formData().get('title')); formData.append('image', request.formData().get('file')); // 直接传文件 const accessToken = localStorage.getItem('access_token'); const csrfToken = localStorage.getItem('csrftoken') || document.cookie.match(/csrftoken=([^;]+)/)[1]; const response = await fetch('http://127.0.0.1:8000/posts', { method: 'POST', credentials: 'include', headers: { "Authorization": `Bearer ${accessToken}`, "X-CSRFToken": csrfToken // 不要手动设置Content-Type,浏览器会自动添加正确的multipart边界 }, body: formData, }); // 后续代码保持不变 }
- 后端序列化器处理base64:自定义字段将base64字符串转为File对象(需安装
Pillow依赖)。
内容的提问来源于stack exchange,提问作者Rolegur
相关产品推荐
相关产品推荐

