关于socket.io将异常信息直接以ack的形式返回给客户端的方法

关于socket.io将异常信息直接以ack的形式返回给客户端的方法

socket.io支持request-response机制,原理就是使用一个ackId来保证请求与响应的一一对应
而当发生异常的时候(一般就是参数验证异常),nest默认情况下的验证管道是通过emit接口返回给客户端一个exception事件,如果客户端使用了ack的逻辑并且进行了等待,这种情况下就无法等到对应的ack数据了
socket.io的协议如网址:https://socket.nodejs.cn/docs/v4/socket-io-protocol/#test-suite,默认的编码器是socket.io-parser,通过socket.conn.send可以发送socket.io编码后的数据给客户端,因此,如果希望将socket.io验证管道的异常通过ack数据包返回到客户端,那么整体的逻辑就是将异常信息通过socket.io-parser编码,然后使用socket.conn.send进行编码后数据的直接发送。
根据https://socket.nodejs.cn/docs/v4/socket-io-protocol/#test-suitesocket.io的协议,那么这里遇到个问题就是如何获取到event数据报的ack的id编号,这里有两个方向:

  • 直接从socket提供的api中获取,很遗憾,找了资料找不到对应的接口
  • socket.io支持自定义解析器,只需要稍微修改一下解析器解析过程,将ack的id信息添加到请求数据中,这样就可以在异常过滤器中通过ctx.getData()获取的id信息,然后进行响应的编码发送操作即可

实现

主要需要修改两个位置:

  1. 解析器解析过程中将ackId添加到用户请求数据中
    // 将ackId添加到请求数据中,这样就可以通过验证管道、异常过滤器获取到对应的ackid,然后进行正常的数据ack响应
    if (packet.hasOwnProperty("data")) {
        const temp = packet.data[1]
        packet.data[1] = {
            _ackId: packet.id,
            data: temp,
        }
    }
    
    这样修改之后,在使用的时候就需要使用@MessageBody("data")的形式进行数据获取
  2. 异常过滤器进行截取异常数据返回ack数据包
    import { ArgumentsHost, Catch } from "@nestjs/common"
    import { BaseWsExceptionFilter, WsException } from "@nestjs/websockets"
    import { Socket } from "socket.io"
    import * as parser from "socket.io-parser"
    
    // 异常一般就是验证管道返回的异常,这里先针对这种环境处理一下
    @Catch(WsException)
    export class WsExceptionFilter extends BaseWsExceptionFilter {
        catch(exception: WsException, host: ArgumentsHost) {
            const ctx = host.switchToWs()
            const socket = ctx.getClient<Socket>()
            const requestData = ctx.getData()
    
            if (requestData._ackId != undefined) {
                const encoder = new parser.Encoder()
                const temp = encoder.encode({
                    type: parser.PacketType.ACK,
                    data: [exception.getError()],
                    id: requestData._ackId,
                    nsp: "/",
                })
                socket.conn.send(temp[0])
            } else {
                socket.emit("exception", exception.getError())
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值