背景
利用netty创建服务端,然后与websocket建立连接,发现一直出现能够接收到前端的请求,但是无法建立正确的websocket连接。
正确代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("收到客户端消息,此时一共有多少个用户建立连接:" + NettyServer.user.keySet()); if (msg instanceof FullHttpRequest) { FullHttpRequest request = (FullHttpRequest) msg; if (!request.decoderResult().isSuccess() || !"websocket".equals(request.headers().get("Upgrade"))) { System.out.println("提前结束"); ctx.channel().close(); return; } String uri = request.uri(); QueryStringDecoder decoder = new QueryStringDecoder(uri); Map<String, List<String>> parameters = decoder.parameters();
String userId = parameters.get("uid").toString(); String newUri = uri.substring(0,uri.indexOf("?")); NettyServer.user.put(userId, ctx.channel());
request.setUri(newUri); } else if (msg instanceof TextWebSocketFrame) { channelRead0(ctx, (TextWebSocketFrame) msg); }
super.channelRead(ctx, msg); }
|
netty创建的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public void start() throws InterruptedException { EventLoopGroup boosGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(boosGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(1000) .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new HttpServerCodec()); ch.pipeline().addLast(new ChunkedWriteHandler()); ch.pipeline().addLast(new HttpObjectAggregator(1024 * 64)); ch.pipeline().addLast(new HttpRequestHandler()); ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10)); } }); System.out.println("netty server start..");
ChannelFuture cf = bootstrap.bind(this.port).sync(); cf.addListener((ChannelFutureListener) channelFuture -> { if (cf.isSuccess()){ System.out.println("监听端口成功"); }else { System.out.println("监听端口失败"); } });
cf.channel().closeFuture().sync(); boosGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }
|
原因分析
ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10));
这一行代码,表示让netty自动去完成websocket握手,而且支持的路径为/ws
。
但是由于前端建立连接时拼接了参数,也就导致了request的uri为/ws?uid=xxx&oid=xxx。这也就意味着自动握手是无法匹配该路径的。
两种解决方案:
第一种就是我们手动的去写对应的握手代码。
第二种就是上边写道的解决方案
1 2 3 4 5 6
| String newUri = uri.substring(0,uri.indexOf("?")); request.setUri(newUri);
super.channelRead(ctx, msg);
|