文章目录
- 1. 需求描述
- 2. 报错信息
- 3. 探索过程
- 1. 使用postman 排除后端错误
- 2. 搜索网上的解决方法
- 3. 解决方法
1. 需求描述
想要在前端上传一个PDF 发票,经过后端解析PDF之后,将想要的值自动回填到对应的输入框中
2. 报错信息
org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.init(FileItemIteratorImpl.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.getMultiPartStream(FileItemIteratorImpl.java:205) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.findNextItem(FileItemIteratorImpl.java:224) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.<init>(FileItemIteratorImpl.java:142) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:252) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:276) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.connector.Request.parseParts(Request.java:2932) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.connector.Request.getParts(Request.java:2834) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:122) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1209) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1043) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:696) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.68.jar:9.0.68]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.68.jar:9.0.68]
at java.lang.Thread.run(Thread.java:750) [na:1.8.0_321]
3. 探索过程
1. 使用postman 排除后端错误
使用postman做接口测试,上传文件确实能够返回正确的值,可以确定是前端代码的问题
我的前端代码
<template>
<div>
<input type="file" @change="onFileChange" accept="application/pdf" />
<button @click="uploadAndFillData" enctype="multipart/form-data">上传并回填数据</button>
<!-- <vxe-button size="mini" status="primary" style="height:25px; margin: 0 0 2px 15px;" @click="uploadAndFillData">导入</vxe-button> -->
<!-- 表单或区域来显示回填的数据 -->
<div v-if="formData">
<!-- 使用formData来显示或更新UI -->
<!-- <p>数据: {{ formData.someKey }}</p> -->
<!-- 如果数据是只读的,可以这样显示 -->
<div>
<p><strong>发票号码:</strong> {{ formData.number }}</p>
<p><strong>开票日期:</strong> {{ formData.date }}</p>
<p><strong>总金额:</strong> {{ formData.amount }}</p>
<p><strong>备注:</strong> {{ formData.remarks }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
selectedFile: null,
formData: null, // 用于存储从后端返回的数据
};
},
methods: {
onFileChange(e) {
this.selectedFile = e.target.files[0];
},
uploadAndFillData() {
// 检查文件是否已经选择
if (!this.selectedFile) {
alert("请先选择一个文件!");
return;
}
const formData = new FormData(); // 创建一个FormData 对象,用于构建将要发送的数据
formData.append("file", this.selectedFile); // 将文件添加到FormData中,字段名为file
this.$http({
url: `/api/invoice/upload`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
// 'Content-Type': 'application/json'
},
// enctype:"multipart/form-data",
})
.then((response) => {
this.formData = response.data; // 将解析后的数据保存到formData中
}).catch((error) => {
console.error("Error uploading file:", error);
alert("上传文件时发生错误!");
});
},
},
};
</script>
2. 搜索网上的解决方法
网上的方法很多,但是都没有能够解决我的问题
- 注释掉header中的content-type,直接404
- 使用axios也是 404
- 在application.yml 中添加文件大小的限制配置【500,还是报原错误】
3. 解决方法
求助于GPT检查前端页面的代码,GPT给出的说法如下,我确实是没有通过Vue插件方式配置axios,所以肯定不能使用this.$http , 顾改用axios的方式向后端发请求,但是之前说了会报错404,猜测可能是因为反向代理配置问题,导致前端并没有通过这个地址请求到后端,所以采用粗暴的方法,直接将后端地址写在axios的url中,并在controller上配置注解@CrossOrigin
修改后的前端代码
<template>
<div>
<input type="file" @change="onFileChange" accept="application/pdf" />
<button @click="uploadAndFillData" enctype="multipart/form-data">上传并回填数据</button>
<!-- <vxe-button size="mini" status="primary" style="height:25px; margin: 0 0 2px 15px;" @click="uploadAndFillData">导入</vxe-button> -->
<!-- 表单或区域来显示回填的数据 -->
<div v-if="formData">
<!-- 使用formData来显示或更新UI -->
<!-- <p>数据: {{ formData.someKey }}</p> -->
<!-- 如果数据是只读的,可以这样显示 -->
<div>
<p><strong>发票号码:</strong> {{ formData.number }}</p>
<p><strong>开票日期:</strong> {{ formData.date }}</p>
<p><strong>总金额:</strong> {{ formData.totalAmount }}</p>
<p><strong>备注:</strong> {{ formData.note }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
selectedFile: null,
formData: null, // 用于存储从后端返回的数据
};
},
methods: {
onFileChange(e) {
this.selectedFile = e.target.files[0];
},
uploadAndFillData() {
// 检查文件是否已经选择
if (!this.selectedFile) {
alert("请先选择一个文件!");
return;
}
const formData = new FormData(); // 创建一个FormData 对象,用于构建将要发送的数据
formData.append("file", this.selectedFile); // 将文件添加到FormData中,字段名为file
// this.$http({
// url: `/api/invoice/upload`,
// method: 'post',
// data: formData,
// headers: {
// 'Content-Type': 'multipart/form-data'
// // 'Content-Type': 'application/json'
// },
// // enctype:"multipart/form-data",
// })
axios.post('http://localhost:8080/invoice/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then((response) => {
this.formData = response.data; // 将解析后的数据保存到formData中
}).catch((error) => {
console.error("Error uploading file:", error);
alert("上传文件时发生错误!");
});
},
},
};
</script>
controller层中注解的配置
@CrossOrigin(origins = "http://localhost:8081", allowedHeaders = "*", allowCredentials = "true")
@PostMapping("/upload")
public ResponseEntity<Object> uploadFile(@RequestParam("file") MultipartFile file) {
try {
// 调用你的文件解析服务
InvoiceSubset parsedData = invoiceService.parsePdfFile(file);
// 返回解析后的数据
return ResponseEntity.ok(parsedData);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error parsing file");
}
}
如此该问题得到解决