处理没有参数的“multipart/form-data”请求异常
Posted
技术标签:
【中文标题】处理没有参数的“multipart/form-data”请求异常【英文标题】:Handling exception of "multipart/form-data" request with no params 【发布时间】:2017-12-22 06:54:04 【问题描述】:我们有一个带有嵌入式码头的 Spring Boot 服务器,该码头公开了一个休息接口。
我们的 RestController 服务使用 "multipart/form-data"(上传文件),我们使用javax.validation
(休眠)来验证请求的参数以在何时返回 BAD_REQUEST参数错误。
这里的问题是,当不给参数时,jetty和spring的过滤器会抛出异常,并且会返回一个500 INTERNAL ERROR给客户端。
在这种情况下,我们希望返回 400 BAD REQUEST,但我们找不到合适的方法,因为在尝试控制器或参数验证之前请求被拒绝(我们使 @NotNull @RequestParam (“文件”))。所以不会调用controllerAdvice
当类型为“multipart/form-data”且没有属性(multipart without any part)时,Jetty 和 Spring 过滤器拒绝 HTTP 请求
你对这个案例有什么建议?
这是堆栈跟踪
WARN 2017/07/17 18:15:52.849 CEST <Thread[qtp1020520290-18]> EXCEPTION
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: Missing content for multipart request
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) ~[javax.servlet-api-3.1.0.jar!/:3.1.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) ~[javax.servlet-api-3.1.0.jar!/:3.1.0]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845) ~[jetty-servlet-9.3.11.v20160721.jar!/:9.3.11.v20160721]
.........................
Caused by: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: Missing content for multipart request
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:111) ~[spring-web-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:85) ~[spring-web-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:76) ~[spring-web-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1099) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:932) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.2.RELEASE.jar!/:4.3.2.RELEASE]
... 42 common frames omitted
【问题讨论】:
你的web.xml?
中有multipart-*
标签
当我给一个文件时它工作得很好;该文件确实已上传,因此配置正确。我使用没有 web.xml 的 spring boot
【参考方案1】:
此异常发生为 IOException
包裹在 org.springframework.web.multipart.MultipartException
中。
只需为 MultipartException
异常类型创建一个标准 Servlet 规范 error-page
错误处理程序,并让您的调度(作为错误)页面报告您想要的状态代码 400。
请注意,如果您这样做,您还需要在类似的 error-page
错误处理程序中捕获 org.eclipse.jetty.http.BadMessageException
,以处理在调用 spring 代码之前发生的类似问题。
另外请注意,有很多类型的错误请求,其中许多通常位于 servlet 上下文之外(或之前),并且无法通过 springs 错误处理来处理,因此这种错误设置对于您的特定需求非常常见.
【讨论】:
我想定义一个 servlet 过滤器来捕获异常并做出响应,但它似乎不是很干净,已经包装了异常,所以我得到了一个包装了 IOException 的 RuntimeException 包装了 MultipartException 我必须在堆栈跟踪中搜索 multipartException 在过滤器和 servlet 中捕获异常并不是 servlet 规范的工作方式。它有自己的完整错误处理层,旨在在最广泛的情况下工作(传入错误、传出错误、包装请求错误、包装响应错误、异步处理错误、异步 i/o 错误、关闭调度线程错误、等)【参考方案2】:您可以编写自己的 ControllerAdvice,类似这样。
@ResponseBody
@ExceptionHandler(MultipartException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorObject handleMultiPartException(
MultipartException e)
//process error message
return new ErrorObject(e);
【讨论】:
请求在尝试控制器之前被拒绝,因此不会使用 controllerAdvice【参考方案3】:我没有成功通过 HandleException (MultipartException) 捕获错误,而是通过将 MultipartFile 设置为可选(必需 = false)然后检查 MultipartFile 变量是否为 null
。
...
@RequestMapping(value = "/csv", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<?> downloadFile(@RequestParam(value = "file", required = false) MultipartFile file)
// Manage the error if no files are uploaded | Not possible to use ExceptionHandler for MultipartFile
if (file == null)
return new ResponseHTTP().WithError("No CSV file selected", HttpStatus.BAD_REQUEST);
...
【讨论】:
以上是关于处理没有参数的“multipart/form-data”请求异常的主要内容,如果未能解决你的问题,请参考以下文章