Angular向Node.js Multer上传图片时后端接收文件为undefined
Multer 上传文件返回 undefined 修复方案
核心原因是前端未按文件上传要求封装请求,且前后端字段配置不匹配,按以下步骤修改即可:
1. 修复前端请求格式问题
Multer 仅能解析 multipart/form-data 格式的请求体,原代码直接发送 JSON 格式数据,文件无法被识别。
修改 bookdata.service.ts
使用 FormData 封装所有参数,不要手动设置 Content-Type 请求头,浏览器会自动补全正确的分隔符参数:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http' import {BooksModel} from '../components/books/books.model'; @Injectable({ providedIn: 'root' }) export class BookdataService { constructor(private http:HttpClient) { } getBooks(){ return this.http.get("http://localhost:3000/books"); } newBook(item: BooksModel){ const formData = new FormData(); // 注意:文件字段名必须和后端 Multer 配置的字段名一致,这里为 image formData.append('image', item.bookImage); formData.append('bookName', item.bookName); formData.append('bookAuthor', item.bookAuthor); formData.append('bookCategory', item.bookCategory); formData.append('bookDescription', item.bookDescription); // 直接返回请求对象,不在 service 里订阅 return this.http.post("http://localhost:3000/books/insert", formData) } }
注意:不要手动添加
Content-Type: multipart/form-data请求头,手动设置会丢失浏览器自动生成的 boundary 参数,导致 Multer 解析失败。
2. 修复 TS 类型定义错误
原代码将文件字段定义为 string 类型,和实际的 File 对象类型不匹配,修改 Angular 端数据模型 books.model.ts:
export class BooksModel{ constructor( public bookName: string, public bookAuthor: string, public bookCategory: string, public bookDescription: string, public bookImage : File // 修改为 File 类型 ){} }
3. 修复前端提交逻辑
原代码提交后立刻跳转页面,不等接口返回,容易导致请求中断,修改 addbook.component.ts:
export class AddbookComponent implements OnInit { title:String="Publish Your Book"; constructor(private bookdataService: BookdataService, private router: Router) { } bookItem= new BooksModel("","","","",null); ngOnInit(): void { } AddBook() { if(!this.bookItem.bookImage){ alert('请先上传书籍封面'); return } // 等接口返回成功后再跳转、提示 this.bookdataService.newBook(this.bookItem).subscribe({ next: (res)=>{ console.log("called"); console.log(this.bookItem.bookImage); alert("发布成功"); this.router.navigate(['/']); }, error: (err)=>{ alert('发布失败:'+err.message) } }) } upload(event: any){ const file=event.target.files[0]; console.log(file); this.bookItem.bookImage=file; } }
4. 修复后端路由取值逻辑
原代码从 req.body.book 里取值,和前端传的字段结构不匹配,且硬编码了图片 contentType,修改 addbookRoutes.js 的 /insert 路由:
booksRouter.post('/insert',upload.single(`image`),function(req,res){ res.header("Access-Control-Allow-Origin","*") res.header('Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE') console.log(req.body); console.log(req.file); // 增加空值校验,避免未传文件时报错 if(!req.file){ return res.status(400).send({msg: '请上传封面图片'}) } const book = { bookName : req.body.bookName, bookAuthor : req.body.bookAuthor, bookCategory : req.body.bookCategory, bookDescription : req.body.bookDescription, bookImage: { data: fs.readFileSync(path.join('./public/uploads/' + req.file.filename)), contentType: req.file.mimetype, // 用上传文件自带的MIME类型,不要硬编码 } } const newBook = new Bookdata(book); newBook.save().then(()=>{ res.send({msg: '书籍发布成功'}) }).catch(err=>{ res.status(500).send({msg: '保存失败', error: err}) }); });
验证方法
改完后打开浏览器开发者工具的 Network 面板,查看上传请求:
- 请求 Payload 格式为
multipart/form-data - 能看到名为
image的文件条目 - 后端控制台打印
req.file可看到完整文件信息,即代表上传正常。
内容的提问来源于stack exchange,提问作者Elizabeth
相关产品推荐
相关产品推荐

