【发布时间】:2020-12-10 18:35:45
【问题描述】:
我们有一个 SpringBoot 应用程序,并且正在使用 Jersey 来审核传入的 HTTP 请求。
我们实现了一个 Jersey ContainerRequestFilter 来检索传入的 HttpServletRequest 并使用 HttpServletRequest 的 getParameterMap() 方法提取查询和表单数据并将其放入我们的审计中。
这与 getParameterMap() 的 javadoc 一致:
"请求参数是与请求一起发送的额外信息。对于 HTTP servlet,参数包含在查询字符串中或发布 表单数据。”
这里是与过滤器有关的文档:
更新SpringBoot后发现getParameterMap()不再返回表单数据,但还是返回了查询数据。
我们发现 SpringBoot 2.1 是支持我们代码的最后一个版本。在 SpringBoot 2.2 中,Jersey 的版本更新为 2.29,但在查看发行说明后,我们没有看到任何与此相关的内容。
发生了什么变化?为了支持 SpringBoot 2.2 / Jersey 2.29,我们需要进行哪些更改?
这是我们代码的简化版本:
JerseyRequestFilter - 我们的过滤器
import javax.annotation.Priority;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
...
@Provider
@Priority(Priorities.AUTHORIZATION)
public class JerseyRequestFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
@Context
private HttpServletRequest httpRequest;
...
public void filter(ContainerRequestContext context) throws IOException {
...
requestData = new RequestInterceptorModel(context, httpRequest, resourceInfo);
...
}
...
}
RequestInterceptorModel - 地图不填充表单数据,仅查询数据
import lombok.Data;
import org.glassfish.jersey.server.ContainerRequest;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ResourceInfo;
...
@Data
public class RequestInterceptorModel {
private Map<String, String[]> parameterMap;
...
public RequestInterceptorModel(ContainerRequestContext context, HttpServletRequest httpRequest, ResourceInfo resourceInfo) throws AuthorizationException, IOException {
...
setParameterMap(httpRequest.getParameterMap());
...
}
...
}
JerseyConfig - 我们的配置
import com.xyz.service.APIService;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.wadl.internal.WadlResource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
...
@Component
public class JerseyConfig extends ResourceConfig {
...
public JerseyConfig() {
this.register(APIService.class);
...
// Access through /<Jersey's servlet path>/application.wadl
this.register(WadlResource.class);
this.register(AuthFilter.class);
this.register(JerseyRequestFilter.class);
this.register(JerseyResponseFilter.class);
this.register(ExceptionHandler.class);
this.register(ClientAbortExceptionWriterInterceptor.class);
}
@PostConstruct
public void init()
this.configureSwagger();
}
private void configureSwagger() {
...
}
}
完整示例
以下是使用我们的示例项目重新创建的步骤:
- 在此处从 github 下载源代码:
git clone https://github.com/fei0x/so-jerseyBodyIssue
- 使用 pom.xml 文件导航到项目目录
- 运行项目:
mvn -Prun
- 在新终端中运行以下 curl 命令来测试 Web 服务
curl -X POST \ http://localhost:8012/api/jerseyBody/ping \ -H 'content-type: application/x-www-form-urlencoded' \ -d param=Test%20String
- 在日志中您会看到表单参数
- 停止正在运行的项目,ctrl-C
- 将 pom 的父版本更新为 SpringBoot 的较新版本
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.15.RELEASE</version>
到
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.9.RELEASE</version>
- 再次运行项目:
mvn -Prun
- 再次调用 curl 调用:
curl -X POST \ http://localhost:8012/api/jerseyBody/ping \ -H 'content-type: application/x-www-form-urlencoded' \ -d param=Test%20String
- 这次日志会缺少表单参数
【问题讨论】:
-
是否可以创建minimal reproducible example 并将其发布到 github 上?只有bare_minimum_ 才能重现问题。我想玩弄它。
-
@PaulSamsotha 我已经用示例项目和重现步骤更新了问题。谢谢。
标签: spring-boot jersey jax-rs jersey-2.0 spring-jersey