Node.js中HTTPS转HTTP的WebSocket请求代理问题排查
解决Node.js代理服务器HTTPS客户端WebSocket请求失败问题
问题根源分析
你的核心问题出在两个关键点:
changeOrigin配置逻辑错误:当前代码根据目标URL是否为localhost决定是否开启changeOrigin,但实际需求是根据客户端请求是否来自HTTPS环境来判断——云HTTPS网站的请求需要修改Host头匹配本地端点,而本地HTTP网站则不需要。- WebSocket代理未明确禁用TLS:当客户端是HTTPS时,
http-proxy会默认尝试用wss://协议连接目标,但你的目标是HTTP端点,导致TLS握手失败,触发连接断开错误。
修复方案
1. 动态调整changeOrigin配置
根据客户端请求的协议(直接HTTPS或反向代理后的X-Forwarded-Proto头)决定是否开启changeOrigin,确保本地端点收到正确的Host头。
2. WebSocket代理强制禁用TLS
在upgrade事件处理中,明确设置secure: false,强制代理使用ws://协议连接HTTP目标端点,避免不必要的TLS握手。
完整修改代码
import * as express from "express"; import { Server, createServer } from "http"; import { createProxyServer } from "http-proxy"; import { settings } from "./settings" export let port = 3004; let server: Server; // 判断客户端是否为HTTPS请求的工具函数 function isClientHttps(req: express.Request): boolean { // 直接HTTPS请求或反向代理转发的HTTPS请求 return req.secure || req.headers['x-forwarded-proto'] === 'https'; } export function startServer() { const targetURL = settings.URL; const app = express(); server = createServer(app); const proxy = createProxyServer({ target: targetURL, ws: true, headers: { // 自定义请求头 }, }); server.on("upgrade", function (req, socket, head) { proxy.ws(req, socket, head, { changeOrigin: isClientHttps(req), secure: false // 强制禁用TLS,适配HTTP目标端点 }); }); // 所有路由统一处理,避免重复代码 app.use(["/public/*", "/api/*", "/api/query"], function (req, res) { proxy.web(req, res, { changeOrigin: isClientHttps(req) }); }); server.listen(0, () => { port = server?.address()?.port; console.log(`Server started on port ${port}`); }); } export function stopServer() { if (server) { server.close(); } }
额外说明
如果你的代理需要直接接收HTTPS请求(而非通过反向代理),需要额外创建HTTPS服务器并监听upgrade事件:
import * as https from 'https'; import * as fs from 'fs'; // 加载SSL证书文件 const sslOptions = { key: fs.readFileSync('./private-key.pem'), cert: fs.readFileSync('./certificate.pem') }; // 创建HTTPS服务器 const httpsServer = https.createServer(sslOptions, app); httpsServer.on("upgrade", function (req, socket, head) { proxy.ws(req, socket, head, { changeOrigin: true, // HTTPS客户端默认开启changeOrigin secure: false }); }); httpsServer.listen(443, () => console.log('HTTPS proxy running on port 443'));
内容的提问来源于stack exchange,提问作者Clarity
相关产品推荐
相关产品推荐

