java – 使用jersey流式传输大型响应,异步

我想允许客户端(包括非常慢的客户端)从JAX-RS(泽西岛)Web服务下载大文件,我被卡住了.似乎JAX-RS中的异步胖子不支持这一点.

>如果必须等待资源在服务器端可用,AsyncResponse解决了这个问题,但是只允许您只调用一次AsyncResponse.resume(Object).之后,响应正常处理.慢速或恶意客户端将阻塞工作线程,直到传输完所有字节.这里没有异步IO.
> jersey中的ChunkedOutput将块存储在无限的内存中队列中,并且不提供任何公共接口来检查该队列的大小.它专为缓慢的小块流而设计.足够慢的客户端最终会导致OutOfMemoryError.
> StreamingOutput根本不是异步的. StreamingOutput.write(OutputStream)方法应该阻塞,直到写入所有字节.
> Servlet 3.x API确实支持我需要的东西,但我找不到从JAX-RS请求处理程序中获取servlet级别(HttpServletRequest.startAsync)的方法,而不会破坏jerseys内部. – &GT IllegalStateException异常

我没有看到明显的解决方案吗?

解决方法:

有了合理的新版球衣和码头,以下作品:

>将@Suspended AsyncResponse注入到jax-rs请求处理程序方法中.这告诉球衣进入异步模式并保持请求打开.
>注入@Context HttpServletRequest以访问servlet级API.
>调用HttpServletRequest.getAsyncContext()而不是HttpServletRequest.startAsync(),因为jersey已经切换到异步模式并再次这样做会导致IllegalStateException(这是我上面的问题).
>像在servlet环境中一样使用此AsyncContext.泽西岛不抱怨.
>完成后,调用AsyncContext.complete(),然后调用AsyncResponse.cancel().我认为后者是可选的.

我设法以这种方式向100个并发客户端提供10GB文件.线程数从未超过~40个线程,内存消耗很低.我的笔记本电脑的吞吐量约为3GB / s,这有点令人印象深刻.

@GET
public void doAsync(@Suspended final AsyncResponse asyncResponse,
                    @Context HttpServletRequest servletRequest)
        throws IOException {
    assert servletRequest.isAsyncStarted();
    final AsyncContext asyncContext = servletRequest.getAsyncContext();
    final ServletOutputStream s = asyncContext.getResponse().getOutputStream();

    s.setWriteListener(new WriteListener() {

        volatile boolean done = false;

        public void onWritePossible() throws IOException {
            while (s.isReady()) {
                if(done) {
                    asyncContext.complete();
                    asyncResponse.isCancelled();
                    break;
                } else {
                    s.write(...);
                    done = true;
                }
            }
        }
    });
}
上一篇:Java HTTP代理服务器


下一篇:获取错误找不到Java类java.util.ArrayList / List的消息正文编写器