Netty-Websocket 根据URL路由,分发机制的实现

时间:2023-03-08 19:51:36

最近在做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

Netty-Websocket 根据URL路由,分发机制的实现

然后继续看,AttributeMap有一个方法,attr(),返回Attribut,参数key。而Attrbute中有set()方法。

Netty-Websocket 根据URL路由,分发机制的实现

好了,那么接下来一切都好办了,直接上关键代码。

下面是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处理机制