websocket拒绝连接的时候,如何把错误信息响应给客户端的onError事件

一、说在前面的话

本文是上一篇文章的补充,所以很多背景以及过程就不再赘述。

上一篇是把错误信息通过onMessage事件,在和客户端对接的时候发现,每次都要判断响应报文,对现有的逻辑改动较大。

其实,我们本次的需求是在创建ws长连接的时候,把错误提示信息给客户端。

所以本文是介绍,如何把错误信息给到onError事件里。

二、先看效果

在这里插入图片描述
返回的是CloseWebSocketFrame,状态码和原因给到172.27.28.90客户端。

  • 这里的抓包,过滤了ping和pong包。
  • 从上面的Info可以看出,它是一个Connection Close 包,注意不是Text

三、源码实现

            synchronized (this) {
                status = this.resolveUserInfo(auth, deviceId, ctx);
            }

            if (status.equals(ResolveStatus.FAIL)) {
                return;
            }
            // 先建立握手
            this.handleHttpRequest(ctx, (FullHttpRequest) msg);

            if (ResolveStatus.TEMP.equals(status)) {
                this.sendRepeatConnectMessage(ctx);
                return;
            }

  • 这里和上一个版本的不同在于,不是抛自定义的运行时异常,而是直接返回报文。
  • 注意,还是要先建立握手,再发送提示信息–不能跳过握手。因为它非常重要,所以再次贴下代码。

WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(getWebSocketLocation(req), null
                , false, 65536 * commonConfig.getMaxWebsocketLengthTimes());
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
            //把握手消息返回给客户端
            handshaker.handshake(ctx.channel(), req);
        }

下面贴出发送错误提示的代码

private void sendRepeatConnectMessage(ChannelHandlerContext ctx) {
        if (ctx.channel().isActive()) {
            ctx.channel().writeAndFlush(new CloseWebSocketFrame(
                            4001, "repeat connect channel"))
                    .addListener(ChannelFutureListener.CLOSE);
        }
    }
  • 这里的状态码定义为4001,请见下图。

在这里插入图片描述
顺便讲一句,上一篇文章中就返回的是1006状态码。

  • 4000~4999 是可以为我们应用的自定义状态码范围

  • 这里我们使用的是CloseWebSocketFrame,还有其他的见下

        byte opcode;
        if (msg instanceof TextWebSocketFrame) {
            opcode = OPCODE_TEXT;
        } else if (msg instanceof PingWebSocketFrame) {
            opcode = OPCODE_PING;
        } else if (msg instanceof PongWebSocketFrame) {
            opcode = OPCODE_PONG;
        } else if (msg instanceof CloseWebSocketFrame) {
            opcode = OPCODE_CLOSE;
        } else if (msg instanceof BinaryWebSocketFrame) {
            opcode = OPCODE_BINARY;
        } else if (msg instanceof ContinuationWebSocketFrame) {
            opcode = OPCODE_CONT;
        } else {
            throw new UnsupportedOperationException("Cannot encode frame of type: " + msg.getClass().getName());
        }
  • ChannelFutureListener的源码可以看出,在发送消息的同时,会关闭连接。
public interface ChannelFutureListener extends GenericFutureListener<ChannelFuture> {

    /**
     * A {@link ChannelFutureListener} that closes the {@link Channel} which is
     * associated with the specified {@link ChannelFuture}.
     */
    ChannelFutureListener CLOSE = new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) {
            future.channel().close();
        }
    };

    /**
     * A {@link ChannelFutureListener} that closes the {@link Channel} when the
     * operation ended up with a failure or cancellation rather than a success.
     */
    ChannelFutureListener CLOSE_ON_FAILURE = new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) {
            if (!future.isSuccess()) {
                future.channel().close();
            }
        }
    };

    /**
     * A {@link ChannelFutureListener} that forwards the {@link Throwable} of the {@link ChannelFuture} into the
     * {@link ChannelPipeline}. This mimics the old behavior of Netty 3.
     */
    ChannelFutureListener FIRE_EXCEPTION_ON_FAILURE = new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) {
            if (!future.isSuccess()) {
                future.channel().pipeline().fireExceptionCaught(future.cause());
            }
        }
    };

    // Just a type alias
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
WebSocket连接是一种在Web浏览器和服务器之间进行实时双向通信的协议。与传统的HTTP请求-响应协议不同,WebSocket连接允许服务器主动向客户端发送消息,而不需要客户端先发送请求。这种持久连接的特性使得WebSocket非常适合实时应用程序,如聊天应用、实时数据更新等。 要建立WebSocket连接客户端首先需要通过在HTTP请求头中包含Upgrade字段并设置为"websocket"来请求升级到WebSocket协议。如果服务器支持WebSocket,并且同意升级协议,它将返回一个HTTP 101 Switching Protocols响应,并在响应头中包含一些特定于WebSocket的字段。此后,客户端服务器之间的通信将以WebSocket协议进行,可以直接发送和接收消息。 在浏览器中,可以使用JavaScript的WebSocket API来创建和管理WebSocket连接。例如,以下代码演示了如何创建一个WebSocket连接并处理消息: ```javascript const socket = new WebSocket('wss://example.com/socket'); socket.addEventListener('open', () => { console.log('WebSocket连接已打开'); }); socket.addEventListener('message', (event) => { console.log('收到消息:', event.data); }); socket.addEventListener('close', () => { console.log('WebSocket连接已关闭'); }); socket.addEventListener('error', (error) => { console.error('WebSocket发生错误:', error); }); ``` 在服务器端,可以使用各种编程语言和框架来处理WebSocket连接。例如,使用Node.js可以使用`ws`模块来创建WebSocket服务器。以下是一个简单的示例: ```javascript const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (socket) => { console.log('新的WebSocket连接已建立'); socket.on('message', (message) => { console.log('收到消息:', message); }); socket.on('close', () => { console.log('WebSocket连接已关闭'); }); socket.send('欢迎使用WebSocket!'); }); ``` 这只是WebSocket连接的基本概念和示例,实际应用中还涉及更多的处理和安全性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天草二十六_简村人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值