已添加enctype="multipart/form-data"仍触发"Current request is not a multipart request"错误的文件上传问题排查
解决Spring Boot + Vue文件上传的「Current request is not a multipart request」错误
嘿,我一眼就揪出问题所在了!你遇到的这个错误,核心原因是前端axios请求的写法完全搞错了FormData的提交方式,跟你加没加enctype="multipart/form-data"关系不大——毕竟你用axios发送请求时,表单的enctype其实不会生效,得靠axios的配置来正确提交。
问题根源拆解
- FormData放错位置:你把包含文件的FormData放在了
params里,这是URL参数的位置,文件上传的二进制数据必须放在请求体(data字段)里。 - 文件添加不完整:你的
uploadImage方法里只把第一个文件添加到了FormData里,后面的循环只是做了预览,没把所有文件都append进去。 - 请求头配置问题:手动设置请求头可能会干扰浏览器自动生成的
multipart/form-data边界标识,反而导致后端识别不了。
前端(Vue)代码修改方案
重点修改uploadImage和articleCreate这两个方法:
<template> <div class="scale"> <button><b-icon-arrow-left></b-icon-arrow-left></button><span>게시글 생성하기</span> <form enctype="multipart/form-data" method="post" > <div class="d-flex flex-row"> <button style="display:inline-block; margin-right:5%; margin-left:2%" @click.prevent="clickInputTag()" id='addimage'><b-icon-plus class="h1"></b-icon-plus></button> <input hidden ref="plus" name="file" id="file" type="file" accept="image/*" @change.prevent="uploadImage($event)" multiple> <div id="image_container"></div> </div> <div> <b-textarea v-model="content" placeholder="Tall textarea" rows="8"></b-textarea> <b-button @click="articleCreate()" >전송</b-button> </div> </form> </div> </template> <script> import axios from 'axios' export default { name:'ArticleCreate', data(){ return{ content:"", files: new FormData(), } }, methods:{ clickInputTag() { this.$refs['plus'].click() }, uploadImage(event) { console.log(event.target.files) // 清空之前的FormData,避免重复添加 this.files = new FormData(); // 循环添加所有选中的文件到FormData for (var image of event.target.files) { this.files.append("file", image); // 保持name为"file",循环append所有文件 // 预览逻辑不变 var reader = new FileReader(); reader.onload = function(event) { var img = document.createElement("img"); img.setAttribute("src", event.target.result); img.setAttribute("width","25%"); document.querySelector("div#image_container").appendChild(img); }; reader.readAsDataURL(image); } console.log(this.files, typeof this.files) }, articleCreate(){ // 把content也添加到FormData里,适配后端@RequestParam接收 this.files.append("content", this.content); axios({ url:'http://127.0.0.1:8080/article', method:'post', headers: { 'x-access-token': `${localStorage.getItem('token')}`, // 不要手动设置Content-Type!让浏览器自动生成带边界的multipart/form-data }, data: this.files, // 关键:用data字段传递FormData,而非params }) .then(res=>{ this.$router.push({ name:'article'}) console.log(res.data) console.log(this.files) }) .catch(err=>{ console.log(`${localStorage.getItem('token')}`) console.log(this.files) console.log(this.content) console.log(err) }) }, } } </script>
后端(Spring Boot)调整细节
你的后端逻辑基本没问题,但要注意参数名和前端FormData的name一致:
前端append的文件name是"file",所以后端的List参数名要对应改成file,否则Spring无法正确绑定:
@PostMapping("/article") @ApiOperation(value = "게시글 작성") public Object postArticle(@RequestParam String content, @RequestParam(required = true) List<MultipartFile> file) throws IOException { // 原有业务逻辑保持不变 Authentication user = SecurityContextHolder.getContext().getAuthentication(); ResponseEntity response = null; if(user.getPrincipal() == "anonymousUser"){ response = new ResponseEntity<>("Fail", HttpStatus.UNAUTHORIZED); return response; }else { UserDetails user2 = (UserDetails) user.getPrincipal(); Optional<User> userOpt = userDao.findByEmail(user2.getUsername()); Long articleId = articleDao.save(Article.builder() .articleid(null) .id(userOpt.get().getUid()) .createdtime(null) .updatedtime(null) .review(content) .build() ).getArticleid(); List<String> pathName = saveFiles(file); System.out.println(pathName.get(0)); for(int i = 0; i < file.size(); ++i) { imageDao.save(Image.builder() .imageid(null) .articleid(articleId) .imgURL(pathName.get(i)) .build() ); } response = new ResponseEntity<>("게시글 작성 완료", HttpStatus.OK); return response; } }
这样调整后,后端就能正确识别multipart请求,顺利接收文件和内容了。
内容的提问来源于stack exchange,提问作者loare
相关产品推荐
相关产品推荐

