Nuxt3 useFetch POST请求:服务端API路由丢失File对象
问题描述
- 客户端侧的数据包含完整的File对象
- 服务端返回的请求体为空对象

请问我的File对象去向何处?
客户端上传代码
const handleImageUpload = async (evt: Event) => { const target = evt.target as HTMLInputElement if (target.files) { const file = target.files[0] const upload: iUpload = { name: file.name, type: file.type, file } console.log("data from client", upload) try { const { data, error } = await useFetch(constants.imageUploadApiUrl, { headers: { "Content-type": "application/json" }, method: 'POST', body: upload }) console.log("data from server", data.value) } catch (error) { console.log(error) } } }
服务端API路由代码
import { getQuery, readBody } from "h3" import { iUpload } from "~~/helpers/interfaces" export default defineEventHandler(async (event) => { try { const query = getQuery(event) const body = await readBody(event) as iUpload return { body } } catch (error: any) { return { error: error.message } } })
iUpload接口定义
export interface iUpload { name: string; type: string; file: File; }
问题原因与解决方案
问题原因
你用Content-type: application/json提交请求,但File对象无法被JSON序列化。当JSON.stringify处理包含File的对象时,会把File转为空对象{},导致服务端接收到的请求体为空。
解决方案
文件上传必须用multipart/form-data格式,改用FormData包装数据:
1. 修改客户端代码
const handleImageUpload = async (evt: Event) => { const target = evt.target as HTMLInputElement if (target.files) { const file = target.files[0] const formData = new FormData() // 追加文件与字段 formData.append('file', file) formData.append('name', file.name) formData.append('type', file.type) console.log("data from client", formData) try { const { data, error } = await useFetch(constants.imageUploadApiUrl, { method: 'POST', body: formData // 无需手动设置Content-type,浏览器会自动添加带边界标识的multipart/form-data }) console.log("data from server", data.value) } catch (error) { console.log(error) } } }
2. 修改服务端API代码
用h3的readMultipartFormData解析FormData:
import { getQuery, readMultipartFormData } from "h3" import { writeFile } from 'fs/promises' import { join } from 'path' export default defineEventHandler(async (event) => { try { const query = getQuery(event) const formData = await readMultipartFormData(event) if (!formData) { return { error: '未接收到表单数据' } } // 解析表单内容 const uploadData: Record<string, any> = {} let fileBuffer: Buffer | null = null for (const item of formData) { if (item.name === 'file') { fileBuffer = item.data uploadData.fileName = item.filename uploadData.fileType = item.type } else { uploadData[item.name] = item.data.toString() } } // 可选:将文件保存到服务器 if (fileBuffer && uploadData.fileName) { const savePath = join(process.cwd(), 'public/uploads', uploadData.fileName) await writeFile(savePath, fileBuffer) } return { body: uploadData } } catch (error: any) { return { error: error.message } } })
3. 调整iUpload接口(可选)
服务端不再接收File对象,可更新接口匹配实际接收的数据:
export interface iUpload { name: string; type: string; fileName?: string; fileType?: string; }
内容的提问来源于stack exchange,提问作者Olanrewaju Ibironke
相关产品推荐
相关产品推荐

