123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package com.dzdy.dim.handler.websocket;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.*;
- import io.netty.handler.codec.http.*;
- import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
- import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
- import io.netty.handler.ssl.SslHandler;
- import io.netty.util.CharsetUtil;
- import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
- import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
- import static io.netty.handler.codec.http.HttpHeaderValues.CLOSE;
- import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
- import static io.netty.handler.codec.http.HttpMethod.GET;
- import static io.netty.handler.codec.http.HttpResponseStatus.*;
- import static io.netty.handler.codec.http.HttpVersion.HTTP_1_0;
- import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
- /**
- * @author : wangzhiyong
- * @date : 2019/6/18 14:58
- * description :
- */
- @ChannelHandler.Sharable
- public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
- public static final WebSocketIndexPageHandler INSTANCE = new WebSocketIndexPageHandler();
- private static final String WEBSOCKET_PATH = "/websocket";
- private WebSocketIndexPageHandler() {
- }
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
- if (updateProtocol(ctx, req)) {
- return;
- }
- // Handle a bad request.
- if (!req.decoderResult().isSuccess()) {
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
- return;
- }
- // Allow only GET methods.
- if (!GET.equals(req.method())) {
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
- return;
- }
- // Send the index page
- if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
- String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, WEBSOCKET_PATH);
- ByteBuf content = WebSocketServerIndexPage.getContent(webSocketLocation);
- FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
- res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
- HttpUtil.setContentLength(res, content.readableBytes());
- sendHttpResponse(ctx, req, res);
- } else {
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));
- }
- }
- /**
- * 协议升级
- * WebSocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法:
- * ws://127.0.0.1:8080/websocket。ws不是http,所以传统的web服务器不一定支持,需要服务器与浏览器同时支持, WebSocket才能正常运行,目前大部分浏览器都支持Websocket。
- * WebSocketServerHandshaker 服务器端Web套接字打开和关闭握手基类
- * WebSocketServerHandshakerFactory 自动检测正在使用的网络套接字协议的版本,并创建一个新的合适的 WebSocketServerHandshaker。
- *
- * @param ctx
- * @param req
- * @return
- */
- private boolean updateProtocol(ChannelHandlerContext ctx, FullHttpRequest req) {
- if ("websocket".equals(req.headers().get("Upgrade"))) {
- WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:9011/websocket", null, false);
- //创建一个握手协议
- WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req);
- if (handshaker == null) {
- /*
- Return that we need cannot not support the web socket version
- 返回不支持websocket 版本
- */
- WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
- } else {
- //开始握手
- handshaker.handshake(ctx.channel(), req);
- }
- return true;
- }
- return false;
- }
- /**
- * 返回http消息
- *
- * @param ctx
- * @param req
- * @param res
- */
- private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
- // Generate an error page if response getStatus code is not OK (200).
- if (res.status().code() != 200) {
- ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
- res.content().writeBytes(buf);
- buf.release();
- HttpUtil.setContentLength(res, res.content().readableBytes());
- }
- // Send the response and close the connection if necessary.
- if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) {
- // Tell the client we're going to close the connection.
- res.headers().set(CONNECTION, CLOSE);
- ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE);
- } else {
- if (req.protocolVersion().equals(HTTP_1_0)) {
- res.headers().set(CONNECTION, KEEP_ALIVE);
- }
- ctx.writeAndFlush(res);
- }
- }
- /**
- * 获取websocket地址
- *
- * @param cp
- * @param req
- * @param path
- * @return
- */
- private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
- String protocol = "ws";
- if (cp.get(SslHandler.class) != null) {
- // SSL in use so use Secure WebSockets
- protocol = "wss";
- }
- return protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path;
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
|