带 SSL 的 Nestjs websocket 网关不工作
Nestjs websocket gateway with SSL is not working
我已经为我的 nest.js server according to this answer 添加了 SSL 支持:
const privateKey = fs.readFileSync('certs/localhost.key', 'utf8');
const certificate = fs.readFileSync('certs/localhost.cert', 'utf8');
const httpsOptions = {key: privateKey, cert: certificate};
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
await app.init();
app.use(cookieParser());
app.enableCors({
origin: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
if (process.env.DEV) {
https.createServer(httpsOptions, server).listen(3006);
console.log('Running in DEV mode using secure HTTPS');
} else {
http.createServer(server).listen(3006);
}
一切正常,我可以使用 HTTPS 访问。
现在我创建了我的 websocket 网关,当我使用 HTTP 时它工作正常:
const options = {
cors: {
origin: true,
methods: ["GET", "POST"],
credentials: true,
}
}
@WebSocketGateway(3007, options)
export class SessionWebsocket {
@WebSocketServer()
private server: Server;
...... And more irrelevant code.
}
每当我尝试通过 HTTPS 访问 websocket 服务器时,我都会在网络中遇到以下错误:
我需要对网关进行任何更改才能使其正常工作吗? The page explaining about the gateways interface 未说明任何有关 SSL 或 TLS 的信息。
编辑:
nestjs服务器运行的端口是3006,websocket服务器的端口是3007,不能运行两个相同的端口。
我连接websocket的方式:
export const SESSION_SOCKET_URL = '//localhost:3007';
this.sessionClient.connect(sessionId, SESSION_SOCKET_URL);
public connect(sessionId: string, socketConnectionString: string) {
const options = {
transportOptions: {
polling: {
extraHeaders: { // This is unrelated to the question, just custom headers, shouldn't affect my issue
'sessionId': sessionId // If undefined, server will generate and send a notify event
}
}
},
}
this.socketClient = io(socketConnectionString, options).connect();
this.socketClient.on('connect', () => {
this.notifyOnConnected.next({
clientId: this.socketClient.id
});
});
}
NestJS Gateway 默认使用 AbstractWsAdapter
,不确定是什么 Adapter 默认实现它。
但是,如果没有自定义适配器,我找不到控制服务器创建的方法,而且我不想启动另一个专用于 websocket 的服务器,而是使用已使用的 http 服务器休息 API.
所以我解决这个问题的方法是,首先在 bootstrap 你的 nestjs 应用程序的地方实现 HTTPS 服务器:
async function bootstrap() {
const privateKey = fs.readFileSync('certs/localhost.key', 'utf8');
const certificate = fs.readFileSync('certs/localhost.cert', 'utf8');
const httpsOptions = {key: privateKey, cert: certificate};
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
const httpsServer = https.createServer(httpsOptions);
app.useWebSocketAdapter(new ExtendedSocketIoAdapter(httpsServer));
app.use(cookieParser());
app.enableCors({
origin: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
await app.init();
httpsServer.listen(3006);
}
基本上在这里你初始化一个 HTTPS 服务器,正如你所看到的,我创建了我自己的适配器,它扩展 IoAdapter
为 socket.io:
export class ExtendedSocketIoAdapter extends IoAdapter {
protected ioServer: io.Server;
constructor(protected server: https.Server) {
super();
const options = {
cors: {
origin: true,
methods: ["GET", "POST"],
credentials: true,
}
}
this.ioServer = new io.Server(server, options);
}
create (port: number) {
console.log('websocket gateway port argument is ignored by ExtendedSocketIoAdapter, use the same port of http instead')
return this.ioServer
}
}
因此,您无需创建新的 https 服务器,而是创建一个新的 IoServer 实例,并传入您在初始化 nest 应用程序时创建的 HTTPS 服务器。
此时忽略@WebSocketGateway({port, options)
中的参数,所以此时可以为空->@WebSocketGateway()
现在 websocket 服务器将 运行 在 HTTPS 服务器之上。
这解决了我的问题。
我已经为我的 nest.js server according to this answer 添加了 SSL 支持:
const privateKey = fs.readFileSync('certs/localhost.key', 'utf8');
const certificate = fs.readFileSync('certs/localhost.cert', 'utf8');
const httpsOptions = {key: privateKey, cert: certificate};
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
await app.init();
app.use(cookieParser());
app.enableCors({
origin: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
if (process.env.DEV) {
https.createServer(httpsOptions, server).listen(3006);
console.log('Running in DEV mode using secure HTTPS');
} else {
http.createServer(server).listen(3006);
}
一切正常,我可以使用 HTTPS 访问。
现在我创建了我的 websocket 网关,当我使用 HTTP 时它工作正常:
const options = {
cors: {
origin: true,
methods: ["GET", "POST"],
credentials: true,
}
}
@WebSocketGateway(3007, options)
export class SessionWebsocket {
@WebSocketServer()
private server: Server;
...... And more irrelevant code.
}
每当我尝试通过 HTTPS 访问 websocket 服务器时,我都会在网络中遇到以下错误:
我需要对网关进行任何更改才能使其正常工作吗? The page explaining about the gateways interface 未说明任何有关 SSL 或 TLS 的信息。
编辑:
nestjs服务器运行的端口是3006,websocket服务器的端口是3007,不能运行两个相同的端口。
我连接websocket的方式:
export const SESSION_SOCKET_URL = '//localhost:3007';
this.sessionClient.connect(sessionId, SESSION_SOCKET_URL);
public connect(sessionId: string, socketConnectionString: string) {
const options = {
transportOptions: {
polling: {
extraHeaders: { // This is unrelated to the question, just custom headers, shouldn't affect my issue
'sessionId': sessionId // If undefined, server will generate and send a notify event
}
}
},
}
this.socketClient = io(socketConnectionString, options).connect();
this.socketClient.on('connect', () => {
this.notifyOnConnected.next({
clientId: this.socketClient.id
});
});
}
NestJS Gateway 默认使用 AbstractWsAdapter
,不确定是什么 Adapter 默认实现它。
但是,如果没有自定义适配器,我找不到控制服务器创建的方法,而且我不想启动另一个专用于 websocket 的服务器,而是使用已使用的 http 服务器休息 API.
所以我解决这个问题的方法是,首先在 bootstrap 你的 nestjs 应用程序的地方实现 HTTPS 服务器:
async function bootstrap() {
const privateKey = fs.readFileSync('certs/localhost.key', 'utf8');
const certificate = fs.readFileSync('certs/localhost.cert', 'utf8');
const httpsOptions = {key: privateKey, cert: certificate};
const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
const httpsServer = https.createServer(httpsOptions);
app.useWebSocketAdapter(new ExtendedSocketIoAdapter(httpsServer));
app.use(cookieParser());
app.enableCors({
origin: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
await app.init();
httpsServer.listen(3006);
}
基本上在这里你初始化一个 HTTPS 服务器,正如你所看到的,我创建了我自己的适配器,它扩展 IoAdapter
为 socket.io:
export class ExtendedSocketIoAdapter extends IoAdapter {
protected ioServer: io.Server;
constructor(protected server: https.Server) {
super();
const options = {
cors: {
origin: true,
methods: ["GET", "POST"],
credentials: true,
}
}
this.ioServer = new io.Server(server, options);
}
create (port: number) {
console.log('websocket gateway port argument is ignored by ExtendedSocketIoAdapter, use the same port of http instead')
return this.ioServer
}
}
因此,您无需创建新的 https 服务器,而是创建一个新的 IoServer 实例,并传入您在初始化 nest 应用程序时创建的 HTTPS 服务器。
此时忽略@WebSocketGateway({port, options)
中的参数,所以此时可以为空->@WebSocketGateway()
现在 websocket 服务器将 运行 在 HTTPS 服务器之上。
这解决了我的问题。