如何在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
相关产品推荐
相关产品推荐

