You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS WebSocket的SubscribeMessage处理器中获取客户端主机名?

NestJS WebSocket中在消息处理器获取客户端主机名的解决方案

核心思路

在handleConnection钩子中获取客户端主机名并挂载到client实例上,后续在@SubscribeMessage装饰的处理器中直接访问该属性即可。

具体实现

情况1:使用Socket.IO适配器

Socket.IO客户端的握手信息中包含请求头,可直接从host头获取主机名:

import {
  WebSocketGateway,
  OnGatewayConnection,
  OnGatewayDisconnect,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
} from '@nestjs/websockets';
import { Socket } from 'socket.io';

@WebSocketGateway()
export class SessionsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  async handleConnection(client: Socket) {
    // 从握手请求头中获取主机名
    const hostname = client.handshake.headers.host;
    // 将主机名挂载到client实例上
    (client as any).hostname = hostname;
  }

  async handleDisconnect() {}

  async afterInit(server) {}

  @SubscribeMessage('init')
  async onInit(
    @MessageBody() event,
    @ConnectedSocket() client: Socket,
  ) {
    try {
      // 直接访问挂载的hostname属性
      const clientHostname = (client as any).hostname;
      console.log('客户端主机名:', clientHostname);
      // 后续业务逻辑
    } catch (error) {
      console.log(error);
      client.close();
    }
  }
}

情况2:使用原生WS适配器

若使用NestJS默认的WS适配器,需通过客户端的socket对象获取远程地址,再反向解析主机名(注意异步处理):

import {
  WebSocketGateway,
  OnGatewayConnection,
  OnGatewayDisconnect,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
} from '@nestjs/websockets';
import * as dns from 'dns';
import { promisify } from 'util';

const reverseLookup = promisify(dns.reverse);

@WebSocketGateway()
export class SessionsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  async handleConnection(client: any) {
    try {
      // 获取客户端远程IP(去除IPv6映射前缀)
      const remoteAddress = client._socket.remoteAddress.replace('::ffff:', '');
      // 反向解析获取主机名
      const hostnames = await reverseLookup(remoteAddress);
      // 取第一个主机名挂载到client实例,解析失败则用IP代替
      client.hostname = hostnames[0] || remoteAddress;
    } catch (err) {
      client.hostname = client._socket.remoteAddress.replace('::ffff:', '');
    }
  }

  async handleDisconnect() {}

  async afterInit(server) {}

  @SubscribeMessage('init')
  async onInit(
    @MessageBody() event,
    @ConnectedSocket() client: any,
  ) {
    try {
      // 访问挂载的hostname属性
      const clientHostname = client.hostname;
      console.log('客户端主机名:', clientHostname);
      // 后续业务逻辑
    } catch (error) {
      console.log(error);
      client.close();
    }
  }
}

说明

  • 不同WebSocket适配器的client对象结构存在差异,需根据实际使用的适配器调整属性访问方式。
  • 若依赖host请求头,需注意部分客户端场景下可能缺失该头,此时可退而求其次使用IP地址或反向解析结果。

内容的提问来源于stack exchange,提问作者Eyal Cohen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 06:15:40