Spring Boot + Jersey 类型过滤器 - 服务的错误请求 400 消耗 MULTIPART_FORM_DATA
Posted
技术标签:
【中文标题】Spring Boot + Jersey 类型过滤器 - 服务的错误请求 400 消耗 MULTIPART_FORM_DATA【英文标题】:Spring Boot + Jersey type filter - Bad request 400 for service Consumes MULTIPART_FORM_DATA 【发布时间】:2018-10-27 11:56:02 【问题描述】:我正在使用 Spring boot v1.5.10 + Jersey v2.25.1,将 jersey 配置为过滤器以访问静态文件夹文件。我收到 HTTP 响应 400 Bad Request 服务使用 MULTIPART_FORM_DATA
。
将 Jersey 配置为过滤器的道具。
spring.jersey.type=filter
如果我删除上述属性,即使用 Jersey 作为 Servlet,该服务正在运行,但我无法访问静态文件夹。
这里是控制器,
@POST
@Path("/save")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public ResponseBean save(
@FormDataParam("fileToUpload") InputStream file,
@FormDataParam("fileToUpload") FormDataContentDisposition fileDisposition,
@FormDataParam("fromData") FormDataDto data)
// stuff
编辑:
GitHub 链接https://github.com/sundarabalajijk/boot-jersey
当您启动应用程序时,spring.jersey.type=filter
http://localhost:8080/(有效)
http://localhost:8080/hello.html(有效)
http://localhost:8080/save(不工作)- 使用邮递员。
当spring.jersey.type=servlet
http://localhost:8080/(有效)
http://localhost:8080/hello.html(不工作)
http://localhost:8080/save(有效)
【问题讨论】:
@Paul Samsotha - 请检查 GitHub 链接和请求。 localhost:8080/save (works) 当 spring.jersey.type=servlet 【参考方案1】:经过一些研究并发现相关问题1,似乎 Spring 的 HiddenHttpMethodFilter
读取了输入流,这使得过滤器链下游的任何其他过滤器都为空。这就是我们在 Jersey 过滤器中收到错误请求的原因;因为实体流是空的。这是来自 Javadoc 的注释
注意:在多部分 POST 请求的情况下,此过滤器需要在多部分处理之后运行,因为它固有地需要检查 POST 正文参数。
所以我们需要做的是配置Jersey过滤器在这个Spring过滤器之前调用2。基于Spring Boot docs,我们可以使用一个属性来轻松配置此过滤器的顺序。
spring.jersey.filter.order
在 Spring Boot 存储库中为HiddenHttpMethodFilter
执行Github search,我们可以看到使用的子类OrderedHiddenHttpMethodFilter,其中顺序设置为-10000
。所以我们想将我们的 Jersey 过滤器的顺序设置为小于那个(更高的优先级)。所以我们可以设置如下值
spring.jersey.filter.order=-100000
如果你现在测试它,它现在应该可以工作了。
我们需要解决的另一件事是 Spring RequestContextFilter
的顺序。这最初被配置为在 Jersey 过滤器之前被命令调用。当我们为 Jersey 过滤器设置上面的顺序配置时,RequestContextFilter
保持原来的位置。所以我们需要改变这一点。我们可以通过添加一个 bean 来覆盖原来的 bean 并设置顺序来做到这一点。
@Bean
public RequestContextFilter requestContextFilter()
OrderedRequestContextFilter filter = new OrderedRequestContextFilter();
filter.setOrder(-100001);
return filter;
现在,如果我们在启动时检查日志,我们应该会看到我们想要的文件管理器顺序。
Mapping filter: 'characterEncodingFilter' to: [/*]
Mapping filter: 'requestContextFilter' to: [/*]
Mapping filter: 'jerseyFilter' to urls: [/*]
Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
Mapping filter: 'httpPutFormContentFilter' to: [/*]
一边
您需要将 Jersey 配置为您的情况的过滤器的原因是因为静态内容。如果您没有为 Jersey 应用程序配置根路径,那么它默认为 /*
,它将占用所有请求,包括那些静态内容。所以当请求静态内容时,Jersey 会抛出 404 错误。我们将 Jersey 配置为过滤器,并告诉它转发它找不到的请求。
如果我们只为 Jersey 配置根路径,那么我们不需要担心静态内容的这个问题,我们可以将 Jersey 配置为默认的 servlet。
要更改 Jersey 应用程序的基本路径,我们可以将 @ApplicatuonPath
注释添加到 ResourceConfig
或使用属性 spring.jersey.application-path
@Component
@ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig
...
或在您的application.properties
spring.jersey.application-path=/api
另见
File upload along with other object in Jersey restful web service。这提供了一些关于如何在多部分请求中接受 JSON 作为正文部分的信息。脚注
1。一些需要关注的问题 [1, 2]2.见Change order of RequestContextFilter in the filter chain
【讨论】:
这很好地解释了这个问题,但是在这么早的时候应用 Jersey 过滤器的解决方案意味着它在 Spring Security 之前运行。 @AdrianBaker 是的,我没有使用 Spring Security,所以我没有考虑到这一点。但这对其他人来说是很好的信息。【参考方案2】:我想接受的答案不再是最新的了。使用 Spring Boot 2 我没有这样的问题。不过有一个问题。我有一个自定义过滤器,它在请求对象上调用getParameterMap
。显然getParameterMap
隐式读取请求的输入流,然后关闭请求,这样其他代码就无法再读取请求正文了。
奇怪的是,设置 spring.jersey.type=servlet
即使事先调用了 getParameterMap
,我也可以获得请求正文,所以我猜 ServletRequest
的实现会有所不同,具体取决于您为 spring.jersey.type
配置的内容。
【讨论】:
以上是关于Spring Boot + Jersey 类型过滤器 - 服务的错误请求 400 消耗 MULTIPART_FORM_DATA的主要内容,如果未能解决你的问题,请参考以下文章
Spring-Boot Jersey:允许 Jersey 提供静态内容
jersey在 spring boot 添加 packages 扫描路径支持