文章目录
- 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 foundat 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中,字段名为filethis.$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");}}
如此该问题得到解决