2017-09-20 237 views
1

我想用Jersey设置Vert.X来处理POST数据(不一定是表单数据)。Vert.x ReadStream <Buffer>到InputStream

泽西岛ContainerRequest.setEntityStream需要在InputStream这是我正在试图建立。不过,我似乎无法避开传递数据,而无需使用bodyHandler或有类似的功能,但限制了输入

final Buffer body = Buffer.buffer(); 
    event 
     .handler(buffer -> { 
      if (!event.response().headWritten()) { 
       body.appendBuffer(buffer); 
       if (body.length() > 10 * 1024 * 1024) { 
        event.response() 
         .setStatusCode(REQUEST_ENTITY_TOO_LARGE.getStatusCode()) 
         .setStatusMessage(REQUEST_ENTITY_TOO_LARGE.getReasonPhrase()) 
         .end(); 
       } 
      } 
     }) 
     .endHandler(aVoid -> { 
      request.setEntityStream(new VertxBufferInputStream(body)); 
      appHandler.handle(request); 
     }); 

VertxBufferInputStream自己的自定义方法读取整个事情到内存是一个简单的包装到VertXbuffer 。通过避免转换为ByteArrayInputStream()来节省一些内存。但它具有整个身体。

我想避免让整个身体流动。我已经尝试了一些非常不好用的代码,最终无法正常工作,因为它阻止了事件循环,因为handler未被调用并正在等待它。

回答

0

这样一个美丽的问题解决:)
您可以在https://github.com/jersey/jersey/blob/12e5d8bdf22bcd2676a1032ed69473cf2bbc48c7/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java#L124 其中具有Netty的球衣集成实现得到灵感。

我相信是完全解决了同样的问题(虽然对于不同的Web服务器,Netty的在这种情况下),那就是:

  1. HTTP请求是在一个事件循环(由Netty的)处理,如必须在不同的线程(非事件循环)上调用ApplicationHandler.handle()方法
  2. 非阻塞API必须转换为阻塞InputStream。这在NettyInputStream执行。它利用了Netty的ByteBuf可以很容易地转换为InputStream的事实,并且因此通过使用LinkedBlockingDeque这些InputStream被转换为单个。 (只是fyi,我不是100%确定提供者,事件循环线程是否保证永远不会阻止哪个是bug)

顺便说一下,这只是处理传入数据。对于响应,您必须实施OutputStream(由Jersey使用)到Vert.X非阻塞API的转换。

+0

谢谢我也研究过它。我的一次尝试与此类似,但仍然阻塞,因为“take()”会阻止。 –

+0

我不明白。这很完美。 'take()'是阻塞的(这是'InputStream.read()'的合约)。重要的部分是我在[1]中描述的,'ApplicationHandler.handle()'必须委托给不同的线程。结果,这个'take()'方法被另一个线程调用,并且一切正常。除非泽西带来了非阻塞API,否则没有其他办法可以实现(不幸的是,它很接近)。 –

+0

正确它是最接近的一个。 (我刚刚得到它的工作) –

0

有两个组件需要。

  1. ,你需要确保你的任何可能阻止使用单独的处理vertx.executeBlocking看到https://github.com/trajano/app-ms/blob/master/ms-engine/src/main/java/net/trajano/ms/engine/JaxRsRoute.java#L128

  2. 您需要处理的两个事件:当新的数据缓冲进来,当它结束。 https://github.com/trajano/app-ms/blob/master/ms-engine/src/main/java/net/trajano/ms/engine/JaxRsRoute.java#L123

  3. 您需要实现一个InputStream,它能够接受来自另一个线程的数据,并在没有数据的情况下接收数据以及接收没有更多输入的消息。 https://github.com/trajano/app-ms/blob/master/ms-engine/src/main/java/net/trajano/ms/engine/internal/VertxBlockingInputStream.java