如何创建多个异步java过滤器?

时间:2014-07-14 21:41:59

标签: java servlets asynchronous filter servlet-filters

我正在尝试使用多个异步过滤器创建一个Java应用程序,但似乎无法让它们一起工作。我认为主要问题在于run()方法我不知道如何将请求传递给链中的下一个过滤器。我已经尝试了chain.doFilter(request, response),但这似乎不起作用,dispatch()上有complete()AsyncContext个API,但似乎关闭整个AsyncContext。似乎必须有另一种方法来实现这一点。下面是我使用的过滤器的片段 - 第二个过滤器看起来几乎相同。

注意:我正在添加标题以尝试找出被调用的内容。

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        final AsyncContext asyncContext = request.startAsync();
        final HttpServletResponse res = (HttpServletResponse) response;
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                res.addHeader("S-AST2", "onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                res.addHeader("S-AST3", "onTimeout");
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                res.addHeader("S-AST4", "onError");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                res.addHeader("S-AST0", "onStartAsync");
            }
        });

        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                res.addHeader("S-AST1", "before");
                // This doesn't seem to work...
                asyncContext.dispatch();
                // ... or this ...
                asyncContext.complete();
                // ... or this ...
                chain.doFilter(request, response);
            }
        });
    }

感谢您的任何见解!

2 个答案:

答案 0 :(得分:5)

这个答案有两个部分。

1)仍然需要chain.doFilter(request, response);

2)这不起作用的原因是在每个过滤器和servlet中我调用了request.startAsync(),它启动了一个新的异步过程,而不是使用现有过程。因此,如果过滤器启动了异步过程,并且servlet也启动了一个异步过程,它将覆盖/忽略在过滤器中启动的过滤器。要解决此问题,您必须通过调用request.isAsyncStarted()来检查是否已启动异步进程,如果是,而不是启动新的异步上下文,则应使用request.getAsyncContext()获取现有异步进程。下面是我为每个servlet和过滤器创建的帮助器类,因此我可以调用AsyncHelper.getAsyncContext(request, response),它将检索现有的AsyncContext,或创建一个新的。

public class AsyncHelper {
    public static AsyncContext getAsyncContext(ServletRequest request, ServletResponse response) {
        AsyncContext asyncContext = null;
        if (request.isAsyncStarted()) {
            asyncContext = request.getAsyncContext();
        }
        else {
            asyncContext = request.startAsync(request, response);
            asyncContext.setTimeout(2000);
        }
        return asyncContext;
    }
}

答案 1 :(得分:0)

我需要修饰响应,我不知道底层servlet是否正在执行异步,或者它是否已经完成。在Jetty 9.1.x上,我通过期待IllegalStateException来解决它 以下示例说明如何包装响应(使用缓冲所有写入响应的自定义BufferingHttpServletResponseWrapper)来拦截输入,以便对其进行修饰。

     @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
     final HttpServletResponse httpServletResponse = (HttpServletResponse) response;

     // Buffer the output to a string in order to calculate its signature and add the signature to a header before it's sent to the client
     final BufferingHttpServletResponseWrapper responseWrapper = new BufferingHttpServletResponseWrapper(httpServletResponse);

     chain.doFilter(httpServletRequest, responseWrapper);

     // This is the only way I can see that will safely let us know if we should treat this as an active async request or not.
     try {
        httpServletRequest.getAsyncContext().addListener(new AsyncListener() {
           @Override
           public void onComplete(AsyncEvent event) throws IOException {
              LOG.debug("onComplete {}", event);
              decorateResponse(responseWrapper);
           }

           @Override
           public void onTimeout(AsyncEvent event) throws IOException {
              LOG.debug("onTimeout {}", event);
           }

           @Override
           public void onError(AsyncEvent event) throws IOException {
              LOG.debug("onError {}", event);
           }

           @Override
           public void onStartAsync(AsyncEvent event) throws IOException {
              LOG.debug("onStartAsync {}", event);
              event.getAsyncContext().addListener(this);
           }
        }
        , httpServletRequest, responseWrapper);
        LOG.debug("After chain.doFilter, async was started");
     } catch (IllegalStateException e) {
        LOG.debug("Async not active it appears... {}", e.getMessage());
        decorateResponse(responseWrapper);
     }
  }