Jersey 2过滤器在客户端请求过滤器中使用容器请求上下文

ogg*_*ter 11 java web-services jersey jersey-client jersey-2.0

我有一个Jersey 2 Web服务,在收到请求后,向另一个Web服务发出另一个请求,以便形成对原始请求的响应.因此,当客户端"A"向我的网络服务"B"发出请求时,"B"向"C"发出请求,作为形成对"A"的响应的一部分.

A-> B-> C ^

我想为Jersey 2 Web服务实现一个基本上执行此操作的过滤器:

  • 客户端"A"将发送一个请求,其标题为"My-Header:first"

  • 当我的Web服务"B"然后发出客户端请求"C"时,它应该附加到该头部,因此它发送一个带有此标题"My-Header:first,second"的请求.

我想将其作为过滤器实现,因此我的所有资源都不必复制附加到请求标头的逻辑.

但是,在Jersey 2中,您可以获得以下4个过滤器:

  • ContainerRequestFilter - 过滤/修改入站请求
  • ContainerResponseFilter - 过滤/修改出站响应
  • ClientRequestFilter - 过滤/修改出站请求
  • ClientResponseFilter - 过滤/修改入站响应

泽西过滤器图

我需要使用来自入站请求的标头,修改它,然后使用它作为出站请求,所以基本上我需要的东西既是ContainerRequestFilter又是ClientRequestFilter.我不认为在同一个过滤器中实现两者都行不通,因为你不知道哪个客户端请求映射到哪个容器请求,或者你呢?

ogg*_*ter 5

我找到了一种不错的方法,无需ThreadLocalContainerRequestFilter和之间进行通信ClientRequestFilter,因为您不能假定响应容器请求而发出的客户端请求将在同一线程上。

我实现此目标的方法是在中的ContainerRequestConext对象中设置属性ContainerRequestFilter。然后,我可以将ContainerRequestContext对象(显式或依赖注入)传递给我ClientRequestFilter。如果使用依赖项注入(如果使用的是Jersey 2,则可能使用的是HK2),那么无需修改任何资源级别逻辑就可以实现所有这些。

ContainerRequestFilter这样的:

public class RequestIdContainerFilter implements ContainerRequestFilter {

@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
    containerRequestContext.setProperty("property-name", "any-object-you-like");
}
Run Code Online (Sandbox Code Playgroud)

并且ClientRequestFilter,需要一个ContainerRequestContext在其构造函数:

public class RequestIdClientRequestFilter implements ClientRequestFilter {

    private ContainerRequestContext containerRequestContext;

    public RequestIdClientRequestFilter(ContainerRequestContext containerRequestContext) {
        this.containerRequestContext = containerRequestContext;
    }

    @Override
    public void filter(ClientRequestContext clientRequestContext) throws IOException {
        String value = containerRequestContext.getProperty("property-name");
        clientRequestContext.getHeaders().putSingle("MyHeader", value);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,这只是将它们绑在一起的一种情况。您将需要一个工厂来创建任何Client或所需的工厂WebTarget

public class MyWebTargetFactory implements Factory<WebTarget> {

    @Context
    private ContainerRequestContext containerRequestContext;

    @Inject
    public MyWebTargetFactory(ContainerRequestContext containerRequestContext) {
        this.containerRequestContext = containerRequestContext;
    }

    @Override
    public WebTarget provide() {
        Client client = ClientBuilder.newClient();
        client.register(new RequestIdClientRequestFilter(containerRequestContext));
        return client.target("path/to/api");
    }

    @Override
    public void dispose(WebTarget target) {

    }
}
Run Code Online (Sandbox Code Playgroud)

然后注册过滤器,并将您的工厂绑定到您的主应用程序上ResourceConfig

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        register(RequestIdContainerFilter.class);
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(MyWebTargetFactory.class).to(WebTarget.class);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)