Angular向Spring Boot传图片+对象时触发MultipartHttpServletRequest类型错误
问题排查:Angular向Spring Boot传图片+对象触发MultipartHttpServletRequest类型错误
触发的错误
Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]
前端Angular代码
addPostWithIMG(image: File, postRequest: PostRequest): Subscription { const headers = new HttpHeaders(); headers.append('Content-Type', ' multipart/form-data content'); var file: FormData = new FormData(); file.append('file', image); file.append('postRequest', JSON.stringify(postRequest)); console.log(file) return this.http.post<PostRequest>(`${this.baseUrl + "multi"}`, file, {headers: headers}).subscribe({ next: (data: any) => { console.log(data) }, error: (err: any) => { console.error(err) }, complete: () => { console.log("Done") } });
后端Spring Boot代码
@PostMapping(path = "multi") public String multi(MultipartHttpServletRequest request) throws IOException { String postJSON = request.getParameter("postRequest"); PostRequest = new Gson().fromJson(post, PostRequest.class); MultipartFile file = request.getFile("file"); Binary files = new Binary(file.getBytes()); File fileToSave = new File("Post/src/main/resources/" + postRequest.getPostId() + ".png"); log.info("file: {}", fileToSave.getAbsolutePath()); if (!fileToSave.exists()) { log.info("file created: {}", fileToSave); fileToSave.createNewFile(); } else { log.info("file already exist: {}", fileToSave); } // Try-with-resource try (OutputStream out = new FileOutputStream(fileToSave.getAbsolutePath())) { out.write(files.getData()); out.flush(); } catch (IOException e) { e.printStackTrace(); } return "Image saved"; }
问题原因及修复方案
1. 前端Content-Type设置错误
手动设置的Content-Type格式完全错误:
- 提交FormData时,HttpClient会自动生成包含
boundary的multipart/form-data请求头,手动设置会丢失这个关键参数,导致后端无法识别为Multipart请求。 - 代码中
headers.append('Content-Type', ' multipart/form-data content');的字符串格式错误,多了空格和冗余的content后缀。
修复后的前端代码:
addPostWithIMG(image: File, postRequest: PostRequest): Subscription { // 移除手动设置的Content-Type,HttpClient会自动处理 const formData = new FormData(); formData.append('file', image); formData.append('postRequest', JSON.stringify(postRequest)); return this.http.post<PostRequest>(`${this.baseUrl}/multi`, formData).subscribe({ next: (data: any) => console.log(data), error: (err: any) => console.error(err), complete: () => console.log("Done") }); }
2. 后端代码存在语法错误
原后端代码有两处明显语法问题,会导致编译/运行错误:
PostRequest = new Gson().fromJson(post, PostRequest.class);:缺少变量名,且post未定义,应改为PostRequest postRequest = new Gson().fromJson(postJSON, PostRequest.class);- 引用
postRequest.getPostId()时,变量名之前未正确定义。
修复后的后端代码:
@PostMapping(path = "multi") public String multi(MultipartHttpServletRequest request) throws IOException { String postJSON = request.getParameter("postRequest"); // 修正变量定义和参数引用 PostRequest postRequest = new Gson().fromJson(postJSON, PostRequest.class); MultipartFile file = request.getFile("file"); if (file == null) { return "No file uploaded"; } Binary files = new Binary(file.getBytes()); File fileToSave = new File("Post/src/main/resources/" + postRequest.getPostId() + ".png"); log.info("file: {}", fileToSave.getAbsolutePath()); if (!fileToSave.exists()) { log.info("file created: {}", fileToSave); fileToSave.createNewFile(); } else { log.info("file already exist: {}", fileToSave); } try (OutputStream out = new FileOutputStream(fileToSave.getAbsolutePath())) { out.write(files.getData()); out.flush(); } catch (IOException e) { e.printStackTrace(); return "Save failed"; } return "Image saved"; }
3. 可选优化:后端使用更清晰的参数接收方式
可以不用直接依赖MultipartHttpServletRequest,改用@RequestParam注解直接接收参数,代码更易读:
@PostMapping(path = "multi") public String multi(@RequestParam("file") MultipartFile file, @RequestParam("postRequest") String postJSON) throws IOException { PostRequest postRequest = new Gson().fromJson(postJSON, PostRequest.class); // 后续存储逻辑同上... return "Image saved"; }
内容的提问来源于stack exchange,提问作者Sonn
相关产品推荐
相关产品推荐

