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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:30:39