Jersey:是不是可以覆盖 Jersey filter() 的返回类型?

Posted

技术标签:

【中文标题】Jersey:是不是可以覆盖 Jersey filter() 的返回类型?【英文标题】:Jersey: Is it possible to override return type of Jersey filter()?Jersey:是否可以覆盖 Jersey filter() 的返回类型? 【发布时间】:2017-01-18 06:03:12 【问题描述】:

这是我的用例:

我已经实现了一个 Jersey 过滤器public void filter(ContainerRequestContext requestContext) //do stuff ,它将拦截对我注册的任何 Jersey 端点的所有传入请求。根据我对传入请求标头的一些验证,我能够通过以下方式拒绝请求:

Response response = Response.status(status).entity(errorMsg).build();
requestContext.abortWith(response);

这就是我一直在做的事情,它对我很有效。但是,现在我需要在实际请求的端点本身内访问 requestContext 中的某些信息。我知道可以这样做:

@Path("/path")
@GET
public ReturnType endpoint(@Context ContainerRequestContext requestContext,
                           @CookieParam("cookieId") String cookieValue,
                           @HeaderParam("headerId") String headerValue, etc..)
    //do stuff

问题是,如果我按照上述方法访问端点上的请求信息,如果过滤器验证失败,我将无法再中止过滤器中的请求,因为我收到以下错误:

java.lang.IllegalStateException: The request cannot be aborted as it is
already in the response processing phase.

似乎如果您在您的 Jersey 端点上定义任何可以在 ContainerRequestContext 中访问的参数,它将不允许您在过滤器中中止过滤器链。

一种解决方法(我还没有尝试过,但假设会起作用)是这样做:如果过滤器验证失败,我不会尝试中止过滤器内的请求,我可以添加一个自定义标头到请求。然后,在端点本身上,我可以检查是否设置了该标头。如果设置了,我知道过滤器验证失败,然后我可以构建一个Response 对象并返回它。如果没有设置,我知道过滤器验证成功,我可以继续处理请求。

但是,为了避免在我拥有的每个 Jersey 端点上手动执行此检查(因此需要过滤器),最好在过滤器处停止请求并在此处返回/中止响应。我认为这首先是过滤器的重点。但是,Jersey 过滤器方法的返回类型是void,我似乎无法覆盖它。

有人能解决我的困境吗?

【问题讨论】:

也许做一些类似this的事情,而不是获取整个请求上下文 谢谢,但我最终弄清楚我做错了什么。会写一个答案。 【参考方案1】:

找出问题的根源。我的过滤器是一个响应过滤器,如下所示:

class ResponseFilter implements ContainerResponseFilter
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext)
        MultivaluedMap<String, Object> headers = responseContext.getHeaders();
        headers.add("Access-Control-Allow-Origin", "http://localhost:9000");
        headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        headers.add("Access-Control-Allow-Headers", "Content-Type" );
        headers.add("Access-Control-Allow-Credentials", "true" );
        if(requestValidationFailed)
            Response response = Response.status(status).entity(error).build();
            requestContext.abortWith(response);
        
    

从上面的代码示例中可以看出,我什至在进行请求验证检查之前就已经定义了响应标头。通过这样做,泽西岛假设我现在处于“响应处理阶段”。当我已经为响应设置标头时,它不会让我中止请求是有道理的。

可能有其他方法可以解决这个问题,但我通过将过滤器分成两个过滤器(两个单独的类)来解决它。

class RequestFilter implements ContainerRequestFilter
    public void filter(ContainerRequestContext requestContext)
        if(requestValidationFailed)
            Response response = Response.status(status).entity(error).build();
            requestContext.abortWith(response);
        


class ResponseFilter implements ContainerResponseFilter
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext)
        MultivaluedMap<String, Object> headers = responseContext.getHeaders();
        headers.add("Access-Control-Allow-Origin", "http://localhost:9000");
        headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        headers.add("Access-Control-Allow-Headers", "Content-Type" );
        headers.add("Access-Control-Allow-Credentials", "true" );
    

我现在可以将@Context@CookieParam@HeaderParam 等参数传递到我的资源类函数中,而无需获取java.io.IllegalStateException。当我的 requestValidationFailed 检查返回 true 并且永远不会调用资源函数时,过滤器链也会成功中止。

【讨论】:

以上是关于Jersey:是不是可以覆盖 Jersey filter() 的返回类型?的主要内容,如果未能解决你的问题,请参考以下文章

Jersey 的 servlet 或过滤器

Jersey中是不是有类似于Spring的HandlerInterceptor的Interceptor

我是不是需要服务器端的“jersey-client”依赖项来支持使用它实现的客户端?

为啥使用 JAX-RS / Jersey?

AngularJS $http、CORS 和 Jersey 的基本身份验证

什么是泽西过滤器?