我正在尝试使用多个异步过滤器创建一个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);
}
});
}
感谢您的任何见解!
答案 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);
}
}