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
相关产品推荐
相关产品推荐

