Netty-Websocket 根据URL路由,分发机制的实现
最近在做netty整合websocket,发现网上很多项目都是最简单的demo,单例的一个项目。
然而公司的项目需要接受几个不同功能的ws协议消息,因此最好是用URL来区分,让页面上采用不同的链接方式。
网上项目出现地址的方法:
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // 如果HTTP解码失败,返回HHTP异常 if(!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } // 构造握手响应返回,本机测试 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8088/websocket", null, false); //注意,这条地址别被误导了,其实这里填写什么都无所谓,WS协议消息的接收不受这里控制 handshaker = wsFactory.newHandshaker(req); if(handshaker == null) { // WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } }
然后,开始看源码,发现ChannelHandlerContext继承的 AttributeMap
然后继续看,AttributeMap有一个方法,attr(),返回Attribut,参数key。而Attrbute中有set()方法。
好了,那么接下来一切都好办了,直接上关键代码。
下面是netty接收到消息处理,第一步首先是http握手,这个没的说。
/** * 接收客户端发送的消息 channel 通道 Read 读 简而言之就是从通道中读取数据,也就是服务端接收客户端发来的数据。但是这个数据在不进行解码时它是ByteBuf类型的 */ @Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { // 传统的HTTP接入 if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, ((FullHttpRequest) msg)); // WebSocket接入 } else if (msg instanceof WebSocketFrame) { if("anzhuo".equals(ctx.attr(AttributeKey.valueOf("type")).get())){ handlerWebSocketFrame(ctx, (WebSocketFrame) msg); System.out.println(1111); }else{ System.out.println(2323); handlerWebSocketFrame2(ctx, (WebSocketFrame) msg); } } }
然后:
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // 如果HTTP解码失败,返回HHTP异常 if (!req.getDecoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } HttpMethod method=req.getMethod(); String uri=req.getUri(); if(method==HttpMethod.GET&&"/webssss".equals(uri)){ //....处理 重点在这里,对于URL的不同,给ChannelHandlerContext设置一个Attribut ctx.attr(AttributeKey.valueOf("type")).set("anzhuo"); }else if(method==HttpMethod.GET&&"/websocket".equals(uri)){ //...处理 ctx.attr(AttributeKey.valueOf("type")).set("live"); } // 构造握手响应返回,本机测试 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( "ws://localhost:7397/websocket", null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } }
握手成功之后,发送消息时会返回第一段代码,因此判断context的Attribut就可以分发路由了,给不同的handlerWebSocketFrame处理机制