我们有一个 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
- 这次日志会缺少表单参数