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

Nuxt3中Pinia转发文件后Rest API收不到数据的解决咨询

Nuxt3 + Pinia 文件上传转发Rest API失败问题

在Nuxt3项目中,我通过Pinia管理状态,用store的action处理文件上传流程:先将文件数据转发到Nuxt3的server/api,再由server/api把数据传给外部Rest API端点。

目前/service/api/upload中打印的请求体内容如下:

Go to upload file Rest API ------WebKitFormBoundaryxlynp2SjAmsIq3Nn
Content-Disposition: form-data; name="file"; filename="myfilename.png"
Content-Type: image/png
....
------WebKitFormBoundaryxlynp2SjAmsIq3Nn--

现在遇到的问题是:Rest API接收不到任何数据,但用Postman以form-data格式、key为"file"发送请求时能正常工作。请问如何在server/api脚本中转换请求体,使其能正确向Rest API发送form-data?


相关代码

Vue/Nuxt 表单部分

<script setup>
const store = useStore();

const file = ref();

const onChange = (event) => {
  file.value = event.target.files[0];
};

const uploadFile = async () => {
  try {
    if (!file.value) return;

    const body = new FormData();
    body.append("file", file.value, file.value.name);
    store.form_data = body;
    store.uploadFile();
    alert("Uploaded");
  } catch (e) {
    console.log(e);
    alert("Error");
  }
};
</script>
<template>
  <input
     type="file"
    accept=".jpg,.jpeg,.png,image/jpeg"
    @change="onChange"
/>   
  <button @click="uploadFile">Upload</button>
</template>

Pinia Store 代码

// /stores/myupload.ts
import { defineStore } from "pinia";
 
export const useStore = defineStore("myupload", {
  state: () => {
    return {
      form_data: null,   
    };
  },
  actions: {
    async uploadFile() {
      console.log(`Go to forward data to /server/api: `, this.form_data);
      try {
        const url = `/api/upload`
        const  { data } = await useFetch(url, {
          method: "POST",
          body: this.form_data,
          headers: {
            "Content-Type": "mutlipart/form-data",
          }
        });
        console.log('success')
      } catch (error) {
        console.log('Error: '+ error);
      }
    }
  },
  ...  
});

Server API 代码

// /service/api/upload
try {
  
   const body = await readBody(event);
   console.log(
   `Go to upload file Rest API`,
        body
   );

   const results = await $fetch(
    `${config.public.myURL}/api/v1/myapiendpoint`,
    {
      method: "POST",
      body: body,
      headers: {
        "Content-Type": "mutlipart/form-data",
        'Accept': '*/*', 
        Authorization: `Bearer ${config.myBEARER}`,
      },
    }
  );
  console.log(`success`);
  return results;
      
} catch (error) {
   console.log("Fehler: " + error);
   throw createError({
     statusCode: 500,
     statusMessage: 'Error on File Upload'
   })
}

问题原因及修复方案

1. 手动设置Content-Type的错误

发送FormData时,浏览器会自动生成包含boundary的Content-Type(格式如multipart/form-data; boundary=----WebKitFormBoundaryxxx),但你手动设置了不带boundary的Content-Type(还拼错成了mutlipart),导致后端无法正确解析form-data。

修复:
删除Pinia中手动设置的Content-Type头:

async uploadFile() {
  console.log(`Go to forward data to /server/api: `, this.form_data);
  try {
    const url = `/api/upload`
    const  { data } = await useFetch(url, {
      method: "POST",
      body: this.form_data
      // 移除手动设置的headers
    });
    console.log('success')
  } catch (error) {
    console.log('Error: '+ error);
  }
}

2. Server端解析请求体的方式错误

readBody(event)会把请求体解析成纯文本,无法被外部Rest API识别为form-data。需要改用专门的form-data解析方式,或者直接转发原始请求体。

方案一:重新构建FormData转发

修改/service/api/upload代码:

// /service/api/upload
export default defineEventHandler(async (event) => {
  try {
    // 解析multipart格式的请求体
    const formParts = await readMultipartFormData(event);
    if (!formParts) {
      throw createError({ statusCode: 400, statusMessage: '无表单数据' });
    }

    // 重新构建FormData对象
    const formData = new FormData();
    for (const part of formParts) {
      if (part.name === 'file') {
        formData.append('file', new Blob([part.data]), part.filename);
      }
    }

    const results = await $fetch(
      `${config.public.myURL}/api/v1/myapiendpoint`,
      {
        method: "POST",
        body: formData,
        headers: {
          Authorization: `Bearer ${config.myBEARER}`
          // 无需手动设置Content-Type,ofetch会自动处理
        },
      }
    );
    console.log(`success`);
    return results;
  } catch (error) {
    console.log("Fehler: " + error);
    throw createError({
      statusCode: 500,
      statusMessage: 'Error on File Upload'
    })
  }
});

方案二:直接转发原始请求体(更高效)

如果只是做请求转发,可以直接传递原始请求体和正确的Content-Type:

// /service/api/upload
export default defineEventHandler(async (event) => {
  try {
    const results = await $fetch(
      `${config.public.myURL}/api/v1/myapiendpoint`,
      {
        method: "POST",
        body: await readRawBody(event),
        headers: {
          // 复制原始请求的Content-Type(包含boundary)
          'Content-Type': getRequestHeader(event, 'content-type'),
          'Accept': '*/*',
          Authorization: `Bearer ${config.myBEARER}`,
        },
      }
    );
    console.log(`success`);
    return results;
  } catch (error) {
    console.log("Fehler: " + error);
    throw createError({
      statusCode: 500,
      statusMessage: 'Error on File Upload'
    })
  }
});

3. 其他小错误修复

  • Pinia代码中console.log('success)缺少闭合引号,改为console.log('success')
  • 两处mutlipart拼写错误(修复第一步后该代码已删除,无需额外处理)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:44:51