Jersey InputStream 在过滤器中被修改。无法弄清楚如何访问 Jersey Resource 中修改后的 inputStream

Jersey InputStream is modified in filter. Unable to figure out how to access modified inputStream in Jersey Resource

How to use Jersey interceptors to get request body 中所述,我正在修改 ContainerRequestFilter 中的 EntityInputStream。

public filter(ContainerRequest request){
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     InputStream in = request.getEntityInputStream(); 
     try{
           Readerwriter.writeTo(in, out);
           byte[] requestEntity = out.toByteArray();

           // DO SOMETHING WITH BYTES HERE

           request.setEntityInputStream(new ByteArrayInputStream(requestEntity));

      }/// error handling code here  
}

但是,后来我不知道如何访问修改后的 InputStream。我可以在资源中获取 ServletContext,但我不知道如何获取我在过滤器中实际修改的对象,即 ContainerRequest。

我可以做这样的事情吗?当我尝试这个时,Jersey 无法启动:

@Post
@Path("/test")
public Response test(@Context ContainerRequest cr){
     // blah blah
     return....
}

球衣错误:

缺少方法 public javax.ws.rs.core.Response example.TestController.test(com.sun.jersey.spi.container.ContainerRequest) 的依赖项,注释为 POST 资源,class example.TestController, 未被识别为有效的资源方法。

我卡在旧版本的球衣 1.8 上,所以我不确定这是否是问题的一部分。

您需要做的就是在您的资源方法中接受一个 InputStream 作为实体主体。如果你想要 ByteArrayInputStream 就投它。

@POST
public Response post(InputStream in) {
    ByteArrayInputStream bin = (ByteArrayInputStream)in;
}

如果您还不知道,Jersey 如何将请求流(对于请求主体)转换为 Java 类型(例如 JSON 到 POJO)是通过 MessageBodyReaders. You can read more about them at JAX-RS Entity Providers .

Jersey 已经提供了一些标准 readers 用于易于转换的类型,例如 String。大多数内容类型都可以转换为字符串。同样,它有一个 reader 来处理 InputStream。这可能是最简单的转换,因为请求已经作为 InputStream 传入,所以 reader 实际上需要做的就是 return 原始流,这就是得到的传递给我们的方法。

如果我们看一下实现 InputStreamProvider, we can see that that's what actually happens. The original stream is simply returned。由于过滤器发生在 reader 之前,因此 reader 只是 return 我们设置的流。

这是一个使用 Jersey Test Framework

的完整示例
public class StreamFilterTest extends JerseyTest {

    public static class InputStreamFilter implements ContainerRequestFilter {

        @Override
        public ContainerRequest filter(ContainerRequest request) {
            try {
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                InputStream in = request.getEntityInputStream();
                ReaderWriter.writeTo(in, out);

                byte[] requestBytes = out.toByteArray();
                byte[] worldBytes = " World".getBytes(StandardCharsets.UTF_8);
                byte[] newBytes = new byte[requestBytes.length + worldBytes.length];
                System.arraycopy(requestBytes, 0, newBytes, 0, requestBytes.length);
                System.arraycopy(worldBytes, 0, newBytes, requestBytes.length, worldBytes.length);

                request.setEntityInputStream(new ByteArrayInputStream(newBytes));
            } catch (IOException ex) {
                Logger.getLogger(InputStreamFilter.class.getName()).log(Level.SEVERE, null, ex);
                throw new RuntimeException(ex);
            }

            return request;
        }
    }

    @Path("stream")
    public static class StreamResource {

        @POST
        public String post(InputStream in) throws Exception {
            ByteArrayInputStream bin = (ByteArrayInputStream) in;
            StringWriter writer = new StringWriter();
            ReaderWriter.writeTo(new InputStreamReader(bin), writer);
            return writer.toString();
        }
    }

    public static class AppConfig extends DefaultResourceConfig {
        public AppConfig() {
            super(StreamResource.class);
            getContainerRequestFilters().add(new InputStreamFilter());
        }
    }

    @Override
    public WebAppDescriptor configure() {
        return new WebAppDescriptor.Builder()
                .initParam(WebComponent.RESOURCE_CONFIG_CLASS,
                        AppConfig.class.getName())
                .build();
    }

    @Test
    public void should_return_hello_world() {
        String response = resource().path("stream").post(String.class, "Hello");
        assertEquals("Hello World", response);
    }
}

这是测试依赖

<dependency>
    <groupId>com.sun.jersey.jersey-test-framework</groupId>
    <artifactId>jersey-test-framework-grizzly2</artifactId>
    <version>1.17.1</version>
    <scope>test</scope>
</dependency>