在Jersey的生命周期中,如何拦截一个请求?

49

我已经使用Jersey有一年多了,现在遇到一个问题找不到答案:如何拦截(或挂钩)Jersey请求的生命周期?

理想情况下,我希望能够在容器接受来自网络的请求和调用我的处理程序方法之间执行一些自定义过滤/验证/拒绝操作。如果有一种简单的方式按子路径过滤拦截器(例如,在/下的任何内容都有一个拦截器,而在/user/下的任何内容都有另一个拦截器),那就更好了。

谢谢!

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


你想要什么样的过滤、验证和拒绝?例如,你可以创建自己的 MessageBodyWriter/Reader 来处理验证。或者你可以在构造函数中设置 @Context 自定义 HTTP 标头解析或 URI 解析。 - Marc
这个功能的大多数应用与安全有关。例如,我的(非Jersey)Web应用程序将为某些AJAX调用(都在同一路径下)生成一次性使用的nonce到Jersey。拦截器将负责检查此nonce的有效性。 - cww
@Marc,你能详细介绍一下“或者你可以在构造函数中设置@Context来进行自定义HTTP头解析或URI解析”的部分吗? - Mat
4个回答

52

我找到了答案。

首先,创建一个实现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


5
谢谢您提供解决方案,对我们其他人很有用。 - tddmonkey
1
这个有没有注解? - Shekhar
2
如何使用此功能拒绝请求? - Neeraj Jain

10

这个帖子有点旧了,但我当时遇到了一些问题,需要同时拦截请求的前后。在网上长时间搜索后,我终于弄明白了:


这个线程有些陈旧,但我曾经遇到一个问题,需要拦截请求之前和之后。我在网上进行了长时间搜索后,最终找到了解决方法:
<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(...) 在此类中不是有效的。 - David Brossard

0

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

签名是:

public ContainerResponse filter(ContainerRequest request, ContainerResponse response)

然后你可以像这样进行调用:

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

这个能帮到你吗?


-1

你看过Jersey ClientFilter类了吗?

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

签名是:

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

所以你可以开始做一些像这样的事情:

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

1
看起来这只在客户端上运行。你知道服务器是否有类似的过滤机制吗? - cww

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接