Spring 启动 + 球衣类型过滤器 - 服务消费的错误请求 400 MULTIPART_FORM_DATA
Spring Boot + Jersey type filter - Bad request 400 for service Consumes MULTIPART_FORM_DATA
我正在使用 Spring boot v1.5.10 + Jersey v2.25.1,将 jersey 配置为过滤器以访问静态文件夹文件。对于使用 MULTIPART_FORM_DATA
.
的服务,我收到 HTTP 响应 400 Bad Request
将 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 link https://github.com/sundarabalajijk/boot-jersey
当您启动应用程序时,spring.jersey.type=filter
http://localhost:8080/hello.html(有效)
http://localhost:8080/save(不工作)- 使用邮递员。
当spring.jersey.type=servlet
http://localhost:8080/hello.html(不工作)
http://localhost:8080/save(有效)
经过一些研究和发现相关问题1,似乎 Spring 的 HiddenHttpMethodFilter
读取了输入流,这使得任何输入流都为空其他过滤器在过滤器链的下游。这就是我们在 Jersey 过滤器中收到 Bad Request 的原因;因为实体流是空的。这是来自 Javadoc
的说明
NOTE: This filter needs to run after multipart processing in case of a multipart POST request, due to its inherent need for checking a POST body parameter.
所以我们需要做的是将 Jersey 过滤器配置为在此 Spring 过滤器2 之前调用。在 Spring Boot docs 的基础上,有一个 属性 我们可以用来轻松配置此过滤器的顺序。
spring.jersey.filter.order
执行 Github search in the Spring Boot repo for the HiddenHttpMethodFilter
, we can see the subclass that is used 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.需要注意的一些问题 [ , 2 ]
2。参见
我想接受的答案已经不是最新的了。使用 Spring Boot 2 我没有遇到这样的问题。但是有一个问题。我有一个自定义过滤器,它在请求对象上调用 getParameterMap
。显然 getParameterMap
隐式读取请求的输入流,然后将其关闭,这样其他代码就无法再读取请求正文了。
奇怪的是,设置 spring.jersey.type=servlet
即使事先调用了 getParameterMap
,我也可以获得请求正文,所以我猜 ServletRequest
的实现因您的配置而异spring.jersey.type
.
我正在使用 Spring boot v1.5.10 + Jersey v2.25.1,将 jersey 配置为过滤器以访问静态文件夹文件。对于使用 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 link https://github.com/sundarabalajijk/boot-jersey
当您启动应用程序时,spring.jersey.type=filter
http://localhost:8080/hello.html(有效)
http://localhost:8080/save(不工作)- 使用邮递员。
当spring.jersey.type=servlet
http://localhost:8080/hello.html(不工作)
http://localhost:8080/save(有效)
经过一些研究和发现相关问题1,似乎 Spring 的 HiddenHttpMethodFilter
读取了输入流,这使得任何输入流都为空其他过滤器在过滤器链的下游。这就是我们在 Jersey 过滤器中收到 Bad Request 的原因;因为实体流是空的。这是来自 Javadoc
NOTE: This filter needs to run after multipart processing in case of a multipart POST request, due to its inherent need for checking a POST body parameter.
所以我们需要做的是将 Jersey 过滤器配置为在此 Spring 过滤器2 之前调用。在 Spring Boot docs 的基础上,有一个 属性 我们可以用来轻松配置此过滤器的顺序。
spring.jersey.filter.order
执行 Github search in the Spring Boot repo for the HiddenHttpMethodFilter
, we can see the subclass that is used 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.需要注意的一些问题 [
2。参见
我想接受的答案已经不是最新的了。使用 Spring Boot 2 我没有遇到这样的问题。但是有一个问题。我有一个自定义过滤器,它在请求对象上调用 getParameterMap
。显然 getParameterMap
隐式读取请求的输入流,然后将其关闭,这样其他代码就无法再读取请求正文了。
奇怪的是,设置 spring.jersey.type=servlet
即使事先调用了 getParameterMap
,我也可以获得请求正文,所以我猜 ServletRequest
的实现因您的配置而异spring.jersey.type
.