泽西岛:是否有可能覆盖泽西过滤器的返回类型()?

时间:2016-09-10 04:25:59

标签: java jersey jax-rs servlet-filters jersey-2.0

这是我的用例:

我已经实现了一个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端点上手动检查(因此指向过滤器),最好只在过滤器处停止请求并在那里返回/中止响应。我认为这首先是过滤器的重点。但是,泽西过滤器方法的返回类型是void,我似乎无法覆盖它。

任何人都有解决我的困境的方法吗?

1 个答案:

答案 0 :(得分:2)

弄清楚问题的根源是什么。我的过滤器是一个响应过滤器,如下所示:

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并且永远不会调用资源函数时,过滤器链也会成功中止。