问题
I have an exisiting Java application which is exposing REST services. I want to add a new feature in the same application to handle web socket requests (using netty) along with the exisiting REST services. How can I do that without changing my REST services?
回答1:
There are two ways to do this without changing your REST service:
I would suggest you setup a normal netty websocket server and run it parallel on another port (this can happen in the same application).
A more complicated an inefficient solution would be to write a netty http/websocket server which runs on the default port (80/443) and sends all REST requests to your REST service. So basically you would write a sort of HTTP proxy which also hosts the websocket server (could also happen in the same application).
Here is an example of how to write a netty websocket server.
回答2:
You can use a handler before the handler that receives http requests. The basic task of this handler would be to see if the http request contains WebSocket upgrade headers. If that is the case it would complete the handshake and continue to handle the websocket frames otherwise it will pass the http requests to the next handler as follows:
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
}
}
Or you may use a different handler to handle the websocket frames by replacing the http request handler with a WebSocket frames handler once the handshake is completed.
来源:https://stackoverflow.com/questions/52759267/netty-websocket-and-rest-in-same-java-application