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

如何用单个端口运行Express HTTPS服务器与TLS WebSocket服务?

单个端口同时承载HTTPS(Express)与WebSocket/自定义TLS服务的方案

核心结论

可以用单个端口实现,但你直接用tls.connect裸连HTTPS服务器的方式不对——HTTPS服务器是TLS封装的HTTP服务器,完成TLS握手后它会等待客户端发送HTTP请求,而你只建立了TLS连接却没发送HTTP数据,所以请求回调自然不会触发。

方案1:用同一个HTTPS服务器同时处理Express与WebSocket(推荐)

WebSocket本身是基于HTTP的升级协议,完全可以直接挂载到已有的HTTPS服务器上,不需要单独开TLS端口。用ws库实现的示例代码:

import express from 'express';
import https from 'https';
import { WebSocketServer } from 'ws';
import { readFileSync } from 'fs';

const app = express();
// 处理Express页面路由
app.get('/', (req, res) => {
  res.send('<h1>HTTPS页面服务</h1>');
});

// 创建HTTPS服务器
const httpsServer = https.createServer({
  key: readFileSync('./server.key'),
  cert: readFileSync('./server.cert'),
}, app);

// 挂载WebSocket服务
const wss = new WebSocketServer({ server: httpsServer });
wss.on('connection', (ws) => {
  console.log('WebSocket客户端连接');
  ws.on('message', (data) => {
    console.log('收到WebSocket消息:', data.toString());
    ws.send('已收到消息:' + data.toString());
  });
});

httpsServer.listen(3000, () => {
  console.log('服务器运行在 https://localhost:3000');
});

方案2:同一端口同时处理HTTPS与自定义TLS socket(按需使用)

如果确实需要在同一个端口处理非HTTP的自定义TLS协议,需要自己做协议判断:在TLS握手完成后,根据客户端发送的第一个数据包,判断是HTTP请求还是自定义协议,再分发给不同处理逻辑。示例代码:

import express from 'express';
import https from 'https';
import { createServer as createTlsServer } from 'node:tls';
import { readFileSync } from 'fs';

const app = express();
app.get('/', (req, res) => res.send('HTTPS响应'));

const tlsServer = createTlsServer({
  key: readFileSync('./server.key'),
  cert: readFileSync('./server.cert'),
}, (socket) => {
  // 捕获第一个数据包判断协议类型
  socket.once('data', (chunk) => {
    // 检查是否是HTTP请求(以GET/POST等方法开头)
    const isHttpRequest = /^[A-Z]+\s/.test(chunk.toString());
    if (isHttpRequest) {
      // 交给HTTPS服务器处理,把第一个数据包重新塞回socket
      https.createServer({}, app).emit('connection', socket);
      socket.unshift(chunk);
    } else {
      // 处理自定义TLS socket逻辑
      console.log('自定义TLS连接建立');
      socket.on('data', (data) => {
        console.log('收到自定义数据:', data.toString());
        socket.write('自定义响应:' + data.toString());
      });
    }
  });
});

tlsServer.listen(3000, () => {
  console.log('多协议TLS服务器运行在端口3000');
});

关于你测试代码的问题解决

如果你非要用tls.connect连接HTTPS端口并触发请求回调,需要手动发送HTTP请求:

import { connect } from 'node:tls';
const socket = connect({
  host: process.env.RELAY_SERVER_HOST_ORIGIN || 'localhost',
  port: 3000,
  rejectUnauthorized: false, // 本地测试用,生产环境请勿开启
});

socket.on('connect', () => {
  // 发送HTTP GET请求,触发服务器端的req回调
  socket.write('GET / HTTP/1.1\r\nHost: localhost:3000\r\nConnection: close\r\n\r\n');
});

socket.on('data', (data) => {
  console.log('服务器响应:', data.toString());
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 02:34:52