为什么我的请求实体InputStream在ContainerRequestFilter(Spring + Jersey)中始终为空 [英] Why my request entity InputStream is always empty in ContainerRequestFilter (Spring+Jersey)

查看:125
本文介绍了为什么我的请求实体InputStream在ContainerRequestFilter(Spring + Jersey)中始终为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我完全无法在JaxRS ContainerRequestFilter中获取请求有效内容/表单.

I'm totally unable to get the Request payload/form in a JaxRS ContainerRequestFilter.

我的设置:

  • JDK 8
  • SpringBoot 1.3.0.RELEASE
  • Jersey 2.22.1(来自SpringBoot)

这是我的pom :(来自Spring Initialzr)

here's my pom : (from 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:

Here's my JerseyConfig:

@Configuration
public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(HelloController.class);
        register(MyFilter.class);
    }
}

这是我的HelloController:

Here's my 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:

And here's the core part of the problem I have, the 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已被使用.我用Javax ServletFilter尝试过,但我遇到了同样的问题.

As you can see, this is a very lean SpringBoot example using Jersey. However, it looks like the InputStream from the ContainerRequestFilter has already been consumed. I tried it with a Javax ServletFilter and I have the same problem.

Spring-web是否有可能在调用Jersey之前消耗InputStream?

Is it possible that Spring-web consumes the InputStream before calling Jersey?

请帮助我.

编辑

为了测试它,我使用了POSTMAN并发送:

To test it I used POSTMAN and sent:

POST http://localhost:8080/hello

标题:

Content-type = application/x-www-form-urlencoded

Content-type = application/x-www-form-urlencoded

有效载荷:

foo = bar

foo=bar

我的答复是

barbar

我的控制台输出为

我在过滤器中

{}//解决方案#1<-应该像​​foo = bar

{} // Solution #1 <- Should have been something like foo=bar

//解决方案#2<-空字符串

// Solution #2 <- an empty string

EDIT2

即使没有任何自定义过滤器,控制台中也有该消息:

I also have that message in the console, even without any custom Filter :

2015-11-21 20:14:05.438 WARN 4440 --- [nio-8080-exec-2] o.glassfish.jersey.servlet.WebComponent:对URI的servlet请求

2015-11-21 20:14:05.438 WARN 4440 --- [nio-8080-exec-2] o.glassfish.jersey.servlet.WebComponent : A servlet request to the URI http://localhost:8080/hello contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using @FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.

在将InputStream传递给Jersey之前,肯定看起来有其他东西消耗了InputStream,从而使每个Jax-RS Filters | Interceptors都没有状态.

It definitely looks like something else consumes the InputStream before passing it out to Jersey, leaving every Jax-RS Filters|Interceptors without state.

推荐答案

这是解决方案"

在SpringBoot中,如果添加starter-web模块,它将添加spring:webmvc,这似乎与JaxRS和Servlet过滤器不兼容.如果您使用SpringBoot和Jersey,请确保webmvc jar不在类路径中.

In SpringBoot, if you add the starter-web module, it'll add spring:webmvc and this seems to be not compatible with JaxRS and Servlet Filters. If you use SpringBoot and Jersey, make sure the webmvc jar is not on the classpath.

Spring堆栈将使用Servlet的Request InputStream,并且管道中的每个向下拦截器/过滤器将一无所有.

The Spring stack will consume the Servlet's Request InputStream and every downward intercepter/filter in the pipeline will be left with nothing.

这是一段有效的代码片段,可在Servlet过滤器中获取请求的有效负载

Here's a working snipet of code that fetch the Request's payload in a Servlet Filter

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();
    }
}

这篇关于为什么我的请求实体InputStream在ContainerRequestFilter(Spring + Jersey)中始终为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆