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

标签 java web-services jersey jersey-2.0 jersey-client

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

A->B->C

我想为 Jersey 2 网络服务实现一个过滤器,它基本上是这样做的:

  • 客户端“A”将发送一个 header 如下的请求 “我的标题:第一个”

  • 当我的网络服务“B”发出客户端请求“C”时,它应该 附加到该 header ,因此它会发送带有此 header 的请求 “我的标题:第一,第二”。

我想将其实现为过滤器,这样我的所有资源就不必重复附加到请求 header 的逻辑。

但是,在 Jersey 2 中,您会得到这 4 个过滤器:

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

Jersey Filter Diagram

我需要使用来自入站请求的 header ,对其进行修改,然后将其用于出站请求,因此本质上我需要既是 ContainerRequestFilter 又是 ClientRequestFilter 的东西。我不认为在同一个过滤器中实现两者会起作用,因为您不知道哪个客户端请求映射到哪个容器请求,或者您知道吗?

最佳答案

我找到了一个很好的方法来做到这一点,它不使用 ThreadLocalContainerRequestFilterClientRequestFilter 之间进行通信,您可以' 假定为响应容器请求而发出的客户端请求将在同一线程上。

我实现这一点的方法是在 ContainerRequestFilterContainerRequestConext 对象中设置一个属性。然后我可以将 ContainerRequestContext 对象(显式或通过依赖项注入(inject))传递到我的 ClientRequestFilter 中。如果您使用依赖注入(inject)(如果您使用的是 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");
}

还有一个 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);
    }
}

那么这只是将所有这些捆绑在一起的情况。您将需要一个工厂来创建您需要的任何 ClientWebTarget:

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) {

    }
}

然后在你的主应用程序ResourceConfig上注册过滤器并绑定(bind)你的工厂:

public class MyApplication extends ResourceConfig {

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

关于java - Jersey 2 过滤器在客户端请求过滤器中使用容器请求上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24995307/

相关文章:

java - 在没有 Web.xml 的 JAX-RS 上使用 Shiro 过滤器

c# - 我应该如何在不向全世界开放的情况下从桌面应用程序与数据库进行交互?

java - Jersey 如何注释 java.sql.Timestamp 对象

java - 读取 jersey 的 ParamConverter 中的另一个参数

java - 二维数组旋转

JavaFX - 将文本文件中的歌曲对象字段加载到歌曲的 ArrayList 中

java.lang.IllegalStateException : Couldn't read row 0, col -1

Java 不兼容类型错误 Arraylists

java - PUT 响应代码为 204

java - 与 Jersey 和 JSR 相关的 JAX-RS