Websocket ContinuationFrame处理问题

今天测试中发现Chrome在发送WebsocketFrame时,会自动将大于127KB的数据分片传输, 网上有人提到如果服务器支持RFC6455则不会出现这个问题, 但实测Netty使用了Websocket13的handshaker也无法解决这个问题.
那么就需要在服务器端进行处理, 将分片的数据结合在一起之后再交给后面的handler去执行.
用BinaryFrame做例子, 在传递数据时, 会先收到一个BinaryFrame, 它的isFinalFragment位(第一位)是0, 后续的数据会以ContinuationFrame的形式发送, 直到最后一片finalFragment位是1的ContinuationFrame结束, 中间不会穿插其它的Frame.
那么在服务器端我们就可以写一个Handler, 来拼接这些ContinuationFrame:

@Slf4j
public class ContinuationWebSocketFrameHandler extends ChannelInboundHandlerAdapter {

  private ByteBuf data = null;

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof WebSocketFrame) {
      WebSocketFrame frame = (WebSocketFrame) msg;
      if (frame instanceof BinaryWebSocketFrame) {
        if (!frame.isFinalFragment()) {
          if (data != null) {
            data.release();
          }
          ByteBuf buf = frame.content();
          data = ctx.alloc().buffer(buf.readableBytes());
          data.writeBytes(buf);
          buf.release();
          return;
        } else {
          ctx.fireChannelRead(msg);
          if (data != null) {
            data.release();
            data = null;
          }
          return;
        }
      } else if (frame instanceof ContinuationWebSocketFrame) {
        if (data == null) {
          log.error("ContinuationWebSocketFrame找不到初始的BinaryWebSocketFrame");
          frame.content().release();
          return;
        }
        data.writeBytes(frame.content());
        frame.content().release();
        if (frame.isFinalFragment()) {
          ctx.fireChannelRead(new BinaryWebSocketFrame(data));
          data = null;
          return;
        }
      } else {
        if (data != null) {
          data.release();
          data = null;
        }
        ctx.fireChannelRead(msg);
      }
    } else {
      if (data != null) {
        data.release();
        data = null;
      }
      ctx.fireChannelRead(msg);
    }
  }
}

可以看到逻辑还是比较简单的, 判断一个frame是不是finalFragment, 不是的话, 就将数据暂时存入一个ByteBuf里, 直到收到final fragment,再向后传递并重置ByteBuf.

需要注意的是如果业务有传递TextFrame的需求的话, 需要同时处理TextFrame的分片.

你可能感兴趣的:(Websocket ContinuationFrame处理问题)