在 Jersey 生命周期中如何拦截请求?

Posted

技术标签:

【中文标题】在 Jersey 生命周期中如何拦截请求?【英文标题】:How does one intercept a request during the Jersey lifecycle? 【发布时间】:2011-05-20 11:34:54 【问题描述】:

我已经使用 Jersey 一年的大部分时间了,但偶然发现了一个我无法找到答案的问题:如何拦截(或挂钩)Jersey 请求生命周期?

理想情况下,我可以在容器接受来自网络的请求和调用我的处理程序方法之间执行一些自定义过滤/验证/拒绝。如果有一种简单的方法可以通过子路径过滤拦截器(例如,有一个拦截器用于 / 下的任何内容,另一个拦截器用于 /user/ 下的任何内容,等等)。

谢谢!

编辑:为了更清楚一点,这里的一般想法是能够编写一些代码,这些代码将针对许多 API 调用运行,而不必从每个处理程序方法中显式调用该代码。这将减少额外的代码并消除传递请求上下文的需要。

【问题讨论】:

你想要什么样的过滤、验证、拒绝?例如,您可以创建自己的 MessageBodyWriter/Reader 来处理验证。或者你可以在构造函数中设置@Context,用于自定义HTTP头解析或URI解析。 此功能的大多数应用都与安全有关。例如,我的(非泽西岛)Web 应用程序将为泽西岛的某些 AJAX 调用(都在同一路径下)生成一次性随机数。拦截器将负责检查这个 nonce 的有效性。 @Marc 你能告诉更多关于“或者你可以在构造函数中设置 @Context 以进行自定义 HTTP 标头解析或 URI 解析”部分吗? 【参考方案1】:

我找到了答案。

首先,创建一个实现 ContainerRequestFilter 的类。该接口指定以下方法,在该方法中进行过滤。 ContainerRequest 对象包含有关当前请求的信息。

public ContainerRequest filter(ContainerRequest req);

之后,在 web.xml 的 servlet 配置中包含以下 XML

<init-param>
  <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
  <param-value>path.to.filtering.class</param-value>
</init-param>

来源:

http://jersey.576304.n2.nabble.com/ContainerRequestFilter-and-Resources-td4419975.html http://markmail.org/message/p7yxygz4wpakqno5

【讨论】:

感谢您添加您的解决方案 - 它对我们其他人很有用 这个有注释吗? 如何用这个拒绝请求?【参考方案2】:

这个线程有点老了,但我有一段时间拦截了之前和之后请求。在网上找了很久,终于搞明白了:

<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>blah.LoggingFilter</param-value>
</init-param>
<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    <param-value>blah.LoggingFilter</param-value>
</init-param>

然后是这个类:

public class LoggingFilter extends LoggingFilter implements ContainerRequestFilter 

    private static final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
    public static boolean verboseLogging = false;

    @Override
    public ContainerRequest filter(ContainerRequest arg0) 
        startTime.set(System.currentTimeMillis());
        return arg0;
    

    @Override
    public ContainerResponse filter(ContainerRequest request, ContainerResponse response) 
        System.out.println(System.currentTimeMillis() - startTime.get().longValue());
        StringBuilder sb = new StringBuilder();
        sb.append("User:").append((request.getUserPrincipal() == null ? "unknown" : request.getUserPrincipal().getName()));
        sb.append(" - Path:").append(request.getRequestUri().getPath());
        //...
    

这会在开始和结束时截取请求,以便您可以放入计时器或其他任何东西。

这适用于 Jersey 1.17。不确定 2.x。

【讨论】:

@Override public ContainerResponse filter(...) 在这种类型的类中无效。【参考方案3】:

对于服务器部分,我们使用 Jersey 特定类来执行以下操作:ContainerResponseFilter

签名是:

public ContainerResponse filter(ContainerRequest request, ContainerResponse response)

然后您可以进行如下调用:

Object entity  = response.getEntity();
    ... your logic here ...
return response;

这有什么帮助吗?..

【讨论】:

【参考方案4】:

你看过 Jersey @987654321@ 类吗?

我们目前正在使用它来拦截和执行 API 版本等。内置日志过滤器 - 因此您可以查看它们的代码以了解要编写的内容。

签名是:

public ClientResponse handle(final ClientRequest cr) throws ClientHandlerException...

所以你可以从做以下事情开始:

....
cr.getHeaders()
....
return getNext().handle(cr);

【讨论】:

看起来这只适用于客户端。不知道服务器有没有类似的过滤机制?

以上是关于在 Jersey 生命周期中如何拦截请求?的主要内容,如果未能解决你的问题,请参考以下文章

请求生命周期:

SpringFilter生命周期Servlet生命周期bean的生命周期

重学SpringBoot系列之生命周期内的拦截过滤与监听

Asp.net MVC 之请求生命周期

Java WebSocket生命周期

vue生命周期钩子函数如何第二次打开不请求接口