转https://blog.csdn.net/alwaysRise/article/details/121002198
netty+websocket下pipeline中handler无法传递的问题
在ChannelPipeline中责任链的传递
ChannelPipeline pipeline = socketChannel.pipeline(); //websocket协议本身是基于http协议的,所以这边也要使用http解编码器 pipeline.addLast(new HttpServerCodec()); //以块的方式来写的处理器 pipeline.addLast(new ChunkedWriteHandler()); //netty是基于分段请求的,HttpObjectAggregator的作用是将请求分段再聚合,参数是聚合字节的最大长度 pipeline.addLast(new HttpObjectAggregator(8192)); // pipeline.addLast(new ReadTimeoutHandler(60)); pipeline.addLast(httpRequestHandler); //ws://server:port/context_path //ws://localhost:9999/ws //参数指的是contex_path pipeline.addLast(new WebSocketServerProtocolHandler("/xdong",true)); //websocket定义了传递数据的6中frame类型 pipeline.addLast(xdongTextWebSocketFrameHandler);
在责任链中有两个我自定义的handler,分别是httpRequestHandler和xdongTextWebSocketFrameHandler,这两个handler的作用分别是处理http请求下的token身份验证和完成握手升级以及处理握手完成之后接收ws客户端传入的消息。
但是在我的代码过程中发生了问题,客户端能成功和服务器建立通道,但是却无法完成后续的消息传输,网上在线的ws测试客户端和我的服务端建立连接的时候也提示未收到服务端的握手包。
经过大佬的排查发现我在我的handler中并没有通过fire时间将消息给责任链中的下一个handler处理,实际上我虽然建立了通道但是却没有完成握手,更无法处理消息。
其中三个重要的handler在责任链中的顺序是这样的:
pipeline.addLast(httpRequestHandler); //ws://server:port/context_path //ws://localhost:9999/ws //参数指的是contex_path pipeline.addLast(new WebSocketServerProtocolHandler("/xdong",true)); //websocket定义了传递数据的6中frame类型 pipeline.addLast(xdongTextWebSocketFrameHandler);
httpRequestHandler这个handler放第一个的原因是第一次握手的时候,请求实际上还是个http请求, 我可以拿到url中的token完成身份验证的工作。但是完成了之后还需要调用下一个handler完成http到ws协议的升级。
WebSocketServerProtocolHandler这个handler是io.netty包中自带的handler用来完成http协议到websocket协议的升级, 并且明确提到消息处理的handler必须在该handler之后。
xdongTextWebSocketFrameHandler是一个消息处理的handler,在成功建立ws连接后用来接收客户端传输的消息。
在pipeLine中的加入顺序都是addLast, 所以都是有顺序的。在channelRead0方法中处理完当前的逻辑之后需要通过fire事件触发下一个InboundHandler。方法就是ctx.fireChannelRead(((FullHttpRequest) msg).retain())
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, (FullHttpRequest) msg); ctx.fireChannelRead(((FullHttpRequest) msg).retain()); } else if (msg instanceof WebSocketFrame) { ctx.fireChannelRead(((WebSocketFrame) msg).retain()); } }