同一 Java 应用程序中的 Netty websocket 和 Rest
Netty websocket and Rest in same Java application
我有一个公开 REST 服务的现有 Java 应用程序。我想在同一个应用程序中添加一个新功能来处理 Web 套接字请求(使用 netty)以及现有的 REST 服务。如何在不更改 REST 服务的情况下做到这一点?
有两种方法可以在不更改 REST 服务的情况下执行此操作:
我建议您设置一个普通的 netty websocket 服务器并 运行 它在另一个端口上并行(这可能发生在同一个应用程序中)。
一个更复杂的低效解决方案是编写一个 netty http/websocket 服务器,它 运行 在默认端口 (80/443) 上发送所有 REST 请求到你的 REST 服务。所以基本上你会写一种 HTTP 代理,它也托管 websocket 服务器(也可能发生在同一个应用程序中)。
Here 是如何编写 netty websocket 服务器的示例。
您可以在接收 http 请求的处理程序之前使用一个处理程序。此处理程序的基本任务是查看 http 请求是否包含 WebSocket 升级 headers。如果是这种情况,它将完成握手并继续处理 websocket 帧,否则它将把 http 请求传递给下一个处理程序,如下所示:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
public class WebSocketServerHandler extends ChannelInboundHandlerAdapter {
private WebSocketServerHandshaker handshaker;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) msg;
HttpMethod requestMethod = httpRequest.method();
if (containsUpgradeHeaders(httpRequest)) {
if (HttpMethod.GET == requestMethod) {
// Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
getWebSocketLocation(httpRequest), null, false, Integer.MAX_VALUE);
handshaker = wsFactory.newHandshaker(httpRequest);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), httpRequest);
}
}
} else {
//Let the http handler handle the request
ctx.fireChannelRead(msg);
}
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
} else {
throw new IllegalStateException("unknown message: " + msg);
}
}
private boolean containsUpgradeHeaders(HttpRequest httpRequest) {
HttpHeaders headers = httpRequest.headers();
return headers.containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true) && headers
.containsValue(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET, true);
}
private static String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.headers().get(HttpHeaderNames.HOST);
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
//handle the websocket frame
}
}
或者您可以使用不同的处理程序来处理 websocket 帧,方法是在握手完成后将 http 请求处理程序替换为 WebSocket 帧处理程序。
我有一个公开 REST 服务的现有 Java 应用程序。我想在同一个应用程序中添加一个新功能来处理 Web 套接字请求(使用 netty)以及现有的 REST 服务。如何在不更改 REST 服务的情况下做到这一点?
有两种方法可以在不更改 REST 服务的情况下执行此操作:
我建议您设置一个普通的 netty websocket 服务器并 运行 它在另一个端口上并行(这可能发生在同一个应用程序中)。
一个更复杂的低效解决方案是编写一个 netty http/websocket 服务器,它 运行 在默认端口 (80/443) 上发送所有 REST 请求到你的 REST 服务。所以基本上你会写一种 HTTP 代理,它也托管 websocket 服务器(也可能发生在同一个应用程序中)。
Here 是如何编写 netty websocket 服务器的示例。
您可以在接收 http 请求的处理程序之前使用一个处理程序。此处理程序的基本任务是查看 http 请求是否包含 WebSocket 升级 headers。如果是这种情况,它将完成握手并继续处理 websocket 帧,否则它将把 http 请求传递给下一个处理程序,如下所示:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
public class WebSocketServerHandler extends ChannelInboundHandlerAdapter {
private WebSocketServerHandshaker handshaker;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) msg;
HttpMethod requestMethod = httpRequest.method();
if (containsUpgradeHeaders(httpRequest)) {
if (HttpMethod.GET == requestMethod) {
// Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
getWebSocketLocation(httpRequest), null, false, Integer.MAX_VALUE);
handshaker = wsFactory.newHandshaker(httpRequest);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), httpRequest);
}
}
} else {
//Let the http handler handle the request
ctx.fireChannelRead(msg);
}
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
} else {
throw new IllegalStateException("unknown message: " + msg);
}
}
private boolean containsUpgradeHeaders(HttpRequest httpRequest) {
HttpHeaders headers = httpRequest.headers();
return headers.containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true) && headers
.containsValue(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET, true);
}
private static String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.headers().get(HttpHeaderNames.HOST);
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
//handle the websocket frame
}
}
或者您可以使用不同的处理程序来处理 websocket 帧,方法是在握手完成后将 http 请求处理程序替换为 WebSocket 帧处理程序。