Angular 17图片上传提交表单时报TypeError错误求助
Angular图片上传FormData错误排查与解决
问题描述
跟随教程实现Angular图片上传功能时,提交表单后Chrome控制台抛出错误:
TypeError: Argument 2 ('blobValue') to FormData.append must be an instance of Blob
后端路由代码(Node.js + Express + Multer)
const express = require("express"); const router = express.Router(); const Post = require("../models/post"); const multer = require("multer"); const MIME_TYPE_MAP = { "image/png": "png", "image/jpeg": "jpg", "image/jpg": "jpg", }; const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, "Api/upload"); }, filename: (req, file, cb) => { const name = file.originalname.toLowerCase().split(" ").join("-"); const extension = MIME_TYPE_MAP[file.mimetype]; cb(null, name + "-" + Date.now() + "." + extension); }, }); /* Here i post to the Mongo database */ router.post( "", multer({ storage: storage }).single("image"), (req, res, next) => { const post = new Post({ title: req.body.title, content: req.body.content, }); post.save().then((createdPost) => { //console.log(result); res.status(201).json({ message: "Post added succesfully to MongoDB!", postId: createdPost._id, }); }); //console.log(post); } ); /* Here i fetch from the Mongo database */ router.get("", (req, res, next) => { Post.find().then((documents) => { res .status(200) .json({ message: "Post fetched Successfully!", posts: documents }); }); }); /* Here i delete from the Mongo database */ router.delete("/:id", (req, res, next) => { /* console.log(req.params.id); res.status(200).json({ message: "Post has een deleted!" }); */ Post.deleteOne({ _id: req.params.id }).then((result) => { console.log(result); res.status(200).json({ message: "Post has een deleted!" }); }); }); router.put("/:id", (req, res, next) => { const post = new Post({ _id: req.body.id, title: req.body.title, content: req.body.content, }); Post.updateOne({ _id: req.params.id }, post).then((result) => { // console.log(result); res.status(200).json({ message: "Update Post Successful!" }); }); }); router.get("/:id", (req, res, next) => { Post.findById(req.params.id).then((post) => { if (post) { res.status(200).json(post); } else { res.status(404).json({ message: "Post not Found!" }); } }); }); module.exports = router;
Angular PostService代码
import { Injectable } from '@angular/core'; import { Post } from './postModel'; import { Subject } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root', }) export class PostServiceService { private posts: Post[] = []; private postsUpdated = new Subject<Post[]>(); constructor(private http: HttpClient) {} /* getPost(): Observable<Post[]> { const posts = of(this.posts); return posts; } */ /* Here I get posts route */ getPost() { //return [...this.posts]; this.http .get<{ message: string; posts: any }>('http://localhost:4000/api/posts') .pipe( map((postData) => { return postData.posts.map((post: any) => { return { title: post.title, content: post.content, id: post._id, }; }); }) ) .subscribe((transformedtData) => { this.posts = transformedtData; this.postsUpdated.next([...this.posts]); }); } getPostUpdatedListener() { return this.postsUpdated.asObservable(); } getPosts(id: any) { return this.http.get<{ _id: string; title: string; content: string }>( 'http://localhost:4000/api/posts/' + id ); } addPost(title: string, content: string, image: File) { /* const post: Post = { id: id, title: title, content: content, }; */ const postData = new FormData(); postData.append('title', title); postData.append('content', content); postData.append('image', image, title); this.http .post<{ message: string; postId: string }>( 'http://localhost:4000/api/posts', postData ) .subscribe((responseData) => { const post: Post = { id: responseData.postId, title: title, content: content, }; /* const id = responseData.postId; post.id = id; */ //console.log(responseData.message); this.posts.push(post); this.postsUpdated.next([...this.posts]); }); } updatePost(id: string, title: string, content: string) { const post: Post = { id: id, title: title, content: content }; this.http .put('http://localhost:4000/api/posts/' + id, post) .subscribe((response) => /*console.log(response)*/ { const updatedPosts = [...this.posts]; const oldPostsIndex = updatedPosts.findIndex((p) => p.id === post.id); updatedPosts[oldPostsIndex] = post; this.posts = updatedPosts; this.postsUpdated.next([...this.posts]); }); } deletePost(postId: string) { this.http .delete('http://localhost:4000/api/posts/' + postId) .subscribe(() => { const updatedPosts = this.posts.filter((post) => post.id !== postId); this.posts = updatedPosts; this.postsUpdated.next([...this.posts]); }); } }
问题原因与解决方法
原因分析
错误提示FormData.append的第二个参数必须是Blob实例,说明调用addPost方法时传入的image参数不是有效的File/Blob对象。常见场景:
- 模板中文件输入框绑定错误,未正确获取File对象
- 传递参数时误传了其他类型值(如字符串、undefined)
解决步骤
修正组件模板的文件输入绑定
确保文件输入框正确绑定change事件,获取选中的文件:<input type="file" (change)="onImagePicked($event)" accept="image/*">在组件类中实现方法保存File对象:
selectedImage: File | undefined; onImagePicked(event: Event) { const file = (event.target as HTMLInputElement).files?.[0]; if (file) { this.selectedImage = file; } }调用addPost前校验参数
调用服务方法前,确保selectedImage有效:onAddPost(title: string, content: string) { if (!this.selectedImage) { // 提示用户选择图片 return; } this.postService.addPost(title, content, this.selectedImage); }优化服务中的参数校验
在addPost方法中增加校验,避免无效调用:addPost(title: string, content: string, image: File) { if (!(image instanceof File)) { console.error('Invalid image file:', image); return; } const postData = new FormData(); postData.append('title', title); postData.append('content', content); postData.append('image', image, image.name); // 建议用图片原文件名而非title // 后续请求代码 }后端补充图片路径存储(可选)
当前后端仅保存标题和内容,需修改Post模型添加imagePath字段,并在保存时存入路径:const post = new Post({ title: req.body.title, content: req.body.content, imagePath: req.file.path // 可拼接完整访问URL,如`http://localhost:4000/${req.file.path}` });
内容的提问来源于stack exchange,提问作者Zayno lane
相关产品推荐
相关产品推荐

