Nuxt 3.0.0正式版文件上传功能失效问题求助
文件上传问题修复方案
核心错误原因
- 前后端字段不匹配:前端FormData追加的字段名是
file,后端却尝试读取files.photo,导致files.photo为undefined,触发mimetype读取错误。 - Nuxt 3环境下req对象获取错误:正式版Nuxt 3中,请求对象并非
event.req,而是event.node.req。 - fs直接写入文件损坏:
readBody会将请求体解析为JSON格式,无法正确获取二进制文件内容,导致写入文件损坏。
修正后的后端代码(formidable版本)
import formidable from "formidable"; import fs from "fs"; import path from "path"; export default defineEventHandler(async (event) => { // 确保uploads目录存在 const uploadDir = path.join(process.cwd(), "public", "uploads"); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } return new Promise((resolve, reject) => { const form = formidable({ multiples: true }); // Nuxt 3正式版中使用event.node.req form.parse(event.node.req, (err, fields, files) => { if (err) { return reject({ status: "error", message: err.message }); } // 匹配前端的字段名file,处理单个/多个文件情况 const uploadFile = Array.isArray(files.file) ? files.file[0] : files.file; if (!uploadFile) { return resolve({ status: "error", message: "请上传名为file的文件" }); } // 校验图片类型 if (!uploadFile.mimetype.startsWith("image/")) { return resolve({ status: "error", message: "仅支持上传图片类型文件" }); } // 生成唯一文件名 const imageName = `${Date.now()}${Math.round(Math.random() * 100000)}${uploadFile.originalFilename}`; const oldPath = uploadFile.filepath; const newPath = path.join(uploadDir, imageName); // 正确的访问URL const imageUrl = `/uploads/${imageName}`; try { fs.copyFileSync(oldPath, newPath); resolve({ status: "ok", url: imageUrl }); } catch (copyErr) { reject({ status: "error", message: copyErr.message }); } }); }); });
前端代码优化(类型修正)
<template> <v-col cols="12" sm="10"> <v-sheet min-height="70vh" rounded="lg" class="pa-3"> <input type="file" accept="image/*" label="Bild hochladen" @change="onChange" /> </v-sheet> </v-col> </template> <script setup lang="ts"> const onChange = async (e: Event) => { // 类型断言确保e.target是input元素 const input = e.target as HTMLInputElement; const selectedFile = input.files?.[0]; if (!selectedFile) return; const formData = new FormData(); formData.append('file', selectedFile); try { await $fetch(`/api/v1/data/images`, { method: 'POST', body: formData, }); alert('上传成功'); } catch (err) { console.error('上传失败:', err); alert('上传失败,请重试'); } } </script>
fs模块直接处理文件的正确方式
不能用readBody解析二进制文件,需通过流式读取请求体:
import fs from "fs"; import path from "path"; import { createWriteStream } from "fs"; export default defineEventHandler(async (event) => { const { imageName } = event.context.params; const savePath = path.join(process.cwd(), "assets", "article", "images", imageName); // 确保目录存在 const saveDir = path.dirname(savePath); if (!fs.existsSync(saveDir)) { fs.mkdirSync(saveDir, { recursive: true }); } return new Promise((resolve, reject) => { const writeStream = createWriteStream(savePath); // 流式传输请求体到文件 event.node.req.pipe(writeStream); writeStream.on('finish', () => { resolve({ status: "ok", message: "文件保存成功" }); }); writeStream.on('error', (err) => { reject({ status: "error", message: err.message }); }); }); });
注意:此方式需确保前端请求直接发送二进制数据,而非FormData;若用FormData,仍需用formidable解析。
内容的提问来源于stack exchange,提问作者quei
相关产品推荐
相关产品推荐

