最近在做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處理機制
