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

如何在Nuxt3中通过POST请求向Django DRF发送FormData?

问题:Nuxt3中转FormData请求到Django DRF时出现Unsupported Media Type错误

我尝试用Nuxt3作为中转服务器,将前端提交的包含文本数据和图片的FormData请求转发到Django DRF后端,提交表单时遇到Unsupported Media Type: /api/tasks/add/错误。直接用Postman请求后端接口可以正常工作,推测是Nuxt3未正确处理表单数据导致问题。

相关代码细节

前端页面组件代码(pages.vue)

const taskData = reactive({
  title: '',
  city: '',
  description: '',
  category: route.params.cat_slug,
  subCat: '',
  image_1: [],
  image_2: [],
  image_3: []
})

const submitTaskForm = async () => {
  let formData = new FormData()

  formData.append('title', taskData.title)
  formData.append('city', taskData.city)
  formData.append('description', taskData.description)
  formData.append('category', taskData.category)
  formData.append('subCat', taskData.subCat)
  taskData.image_1.forEach((fileItem) => {
    formData.append('image_1', fileItem.file)
  })
  taskData.image_2.forEach((fileItem) => {
    formData.append('image_2', fileItem.file)
  })
  taskData.image_3.forEach((fileItem) => {
    formData.append('image_3', fileItem.file)
  })

  const data = await useFetch('/api/tasks/add/', {
    method: 'POST',
    body: formData
  })

  return data
}

Nuxt服务器端API代码(/server/api/add.post.ts)

export default defineEventHandler(async (event) => {
    const body = await readBody(event)
    const access = getCookie(event, 'access') || null

    try {
        const data = await $fetch(process.env.API_BASE_URL + "/api/tasks/add/", {
            method: "POST",
            body: body,
            headers: {
                Authorization: "Bearer " + access,
            },
        })
        return data

    } catch (error) {
        console.log(error);
        return error
    }
})

Django DRF视图代码

class TasksCreate(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = TasksSerializer
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request):
        data = self.request.data

        title = data['title']
        city = data['city']
        description = data['description']
        category_slug = data['category']
        subCat = data['subCat']
        image_1 = request.FILES.get('image_1', "")
        image_2 = request.FILES.get('image_2', "")
        image_3 = request.FILES.get('image_3', "")

        try:
            if not Subcategories.objects.filter(slug=subCat, category__slug=category_slug).exists():
                return Response(
                    {'error': 'The subcategory does not correspond to the category.', },
                    status=status.HTTP_400_BAD_REQUEST
                )

            task = Task.objects.create(
                title=title,
                city=city,
                description=description,
                slug='%s-%s' % (slugify(title), randint(1000, 10000)),
                category=get_object_or_404(Category, slug=category_slug),
                sub_category = get_object_or_404(Subcategories, slug=subCat),
                created_by=request.user,
                image_1=image_1,
                image_2=image_2,
                image_3=image_3,
            )

            task.save()

            return Response(
                {'task': 'Task created successfully', },
                status=status.HTTP_201_CREATED
            )
        except Exception as e:
            print(e)
            return Response(
                {'error': 'Something went wrong when creating the task'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

解决方案

问题核心是Nuxt服务器端用readBody读取请求体时,会将multipart/form-data格式的数据解析为普通JSON对象,丢失了文件的二进制信息和正确的请求头结构,导致Django无法识别媒体类型。需要修改服务器端代码,正确处理multipart表单数据:

修改后的Nuxt服务器端API代码

export default defineEventHandler(async (event) => {
    // 读取原始multipart表单数据
    const formDataItems = await readMultipartFormData(event);
    const access = getCookie(event, 'access') || null;

    // 重新构建FormData用于转发到Django
    const forwardFormData = new FormData();
    formDataItems?.forEach(item => {
        if (item.filename) {
            // 处理文件字段:将二进制数据转为Blob并添加到FormData
            forwardFormData.append(item.name, new Blob([item.data], { type: item.type }), item.filename);
        } else {
            // 处理普通文本字段:将Buffer转为字符串
            forwardFormData.append(item.name, item.data.toString());
        }
    });

    try {
        const data = await $fetch(process.env.API_BASE_URL + "/api/tasks/add/", {
            method: "POST",
            body: forwardFormData,
            headers: {
                Authorization: "Bearer " + access,
                // 不要手动设置Content-Type,$fetch会自动生成带boundary的正确头
            },
        });
        return data;
    } catch (error) {
        console.error(error);
        return error;
    }
});

关键说明

  1. 使用readMultipartFormData替代readBody:该方法会保留原始multipart数据的结构,包括文件的二进制内容、文件名和MIME类型。
  2. 重新构建FormData:将读取到的multipart项重新组装成标准的FormData对象,确保转发时数据格式正确。
  3. 不要手动设置Content-Type:手动设置会丢失自动生成的boundary参数,后端无法正确解析multipart数据,$fetch会自动处理FormData的请求头。

内容的提问来源于stack exchange,提问作者Minseven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 00:35:31