我完全无法在JaxRS ContainerRequestFilter中获取请求有效内容/表单。
我的设置:
这是我的pom :(来自Spring Initialzr)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
这是我的应用程序类:
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
这是我的JerseyConfig:
@Configuration public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(HelloController.class); register(MyFilter.class); } }
这是我的HelloController:
@Component @Path("/hello") public class HelloController { @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @POST public String onHelloRequest(@FormParam("foo") String foo) { System.out.println(foo); return foo + "bar"; } }
这是我遇到的问题的核心部分,即ContainerRequestFilter:
public class MyFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext ctx) throws IOException { System.err.println("I'm in the filter"); // Solution #1 doesn't work if (ctx instanceof ContainerRequest) { ContainerRequest request = (ContainerRequest) ctx; request.bufferEntity(); Form f = request.readEntity(Form.class); System.err.println(f.asMap().toString()); } // Solution #2 doesn't work either InputStream inputStream = ctx.getEntityStream(); StringBuilder textBuilder = new StringBuilder(); try (Reader reader = new BufferedReader(new InputStreamReader (inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) { int c = 0; while ((c = reader.read()) != -1) { textBuilder.append((char) c); } } System.err.println(textBuilder.toString()); } }
如您所见,这是一个使用Jersey的非常精简的SpringBoot示例。但是,看起来好像已经使用了ContainerRequestFilter中的InputStream。我用JavaxServletFilter尝试过,但我遇到了同样的问题。
Spring-web是否有可能在调用Jersey之前消耗InputStream?
请帮我。
编辑
为了测试它,我使用了POSTMAN并发送:
POST http:// localhost:8080 /你好
标头:
内容类型=应用程序/ x-www-form-urlencoded
有效负载:
foo = bar
我的回应是
巴巴
我的控制台输出是
我在过滤器中
{} //解决方案#1 <-应该像foo = bar这样
//解决方案#2 <-空字符串
酒吧
编辑2
即使没有任何自定义Filter,我在控制台中也有该消息:
2015-11-21 20:14:05.438 WARN 4440 — [nio-8080-exec-2] o.glassfish.jersey.servlet.WebComponent:对URI的Servlet请求http:// localhost:8080 / hello包含表单参数在请求主体中,但是请求主体已被servlet或访问请求参数的servlet过滤器消耗。只有使用@FormParam的资源方法才能按预期工作。通过其他方式消耗请求主体的资源方法将无法正常工作。
肯定看起来是其他东西消耗了InputStream,然后才将其传递到Jersey,使每个Jax-RS Filters | Interceptors都没有状态。
这是“解决方案”
在SpringBoot中,如果添加了starter- web模块,它将添加spring:webmvc,这似乎与JaxRS和Servlet过滤器不兼容。如果使用SpringBoot和Jersey,请确保webmvcjar不在类路径中。
Spring堆栈将使用Servlet的Request InputStream,并且管道中的每个向下拦截器/过滤器将一无所有。
这是一段有效的代码片段,可在Servlet过滤器中获取请求的有效负载
public MyFilter implements Filter { @Override public final void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { getRawFormPayload((HttpServletRequest) request); chain.doFilter(request, response); } protected String getRawFormPayload(HttpServletRequest request) { final int contentLength = request.getContentLength(); final StringBuilder payloadBuilder = new StringBuilder(contentLength); try { final InputStream inputStream = request.getInputStream(); final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, request.getCharacterEncoding())); // Buffer should not be higher than the content-length of the request reader.mark(contentLength + 1); final char[] charBuffer = new char[contentLength + 1]; int bytesRead = -1; while ((bytesRead = reader.read(charBuffer)) > 0) { payloadBuilder.append(charBuffer, 0, bytesRead); } // Reset the buffer so the next Filter/Interceptor have unaltered InputStream reader.reset(); } catch (final IOException e) { this.LOG.error(e.getMessage(), e); } return payloadBuilder.toString(); } }