風雲 (ID: 3)
头衔:论坛版主
等级:大天使
积分:1943
发帖:81 篇
来自:保密
注册:2022/3/30 15:28:53
造访:2026/7/11 18:19:07
发帖:81 篇
来自:保密
注册:2022/3/30 15:28:53
造访:2026/7/11 18:19:07
[ 第 1 楼 ]
回复
@rimifon/asp 的反向代理仅支持普通 http 和 https 代理,遇到 websocket 就不能正常工作了,需要增加一个 upgrade 的特殊处理才行:
const net = require("net");
const tls = require("tls");
const asp = require("@rimifon/asp");
const conf = {
http: 3000, https: 4433, onlisten,
proxy: {
"127.34.56.78": { host: "103.80.27.121", hostname: "exop.cn", port: 443, protocol: "https" }
},
hosts: [
// 默认第一个网站
{ domain: "default", root: "wwwroot/default", rewrite }
],
indexPages: [ "index.html", "default.asp" ]
};
asp.start(conf);
function rewrite(path) {
return path.replace(/^\/(home|api)/, "/default.asp/$1");
}
function onlisten(svr) {
svr.on("upgrade", (req, socket, head) => {
const hostname = req.headers.host?.replace(/\:\d+$/, "") || "default";
const target = conf.proxy[hostname];
if (!target) return;
// 处理 websocket 代理
const isSecure = target.protocol === "https";
const options = {
host: target.host || "127.0.0.1",
port: target.port || (isSecure ? 443 : 80),
servername: target.hostname || target.host
};
const proxySocket = (isSecure ? tls : net).connect(options);
const timeout = setTimeout(() => {
socket.write("HTTP/1.1 504 Gateway Timeout\r\n\r\n");
socket.destroy();
proxySocket.destroy();
}, 10000);
const connectEvent = isSecure ? "secureConnect" : "connect";
proxySocket.on(connectEvent, () => {
clearTimeout(timeout);
const headers = [];
let hostReplaced = false;
for (let i = 0; i < req.rawHeaders.length; i += 2) {
const key = req.rawHeaders[i];
let value = req.rawHeaders[i + 1];
if (key.toLowerCase() === "host") {
value = target.hostname || target.host;
hostReplaced = true;
}
headers.push(`${key}: ${value}`);
}
if (!hostReplaced) {
headers.push(`Host: ${target.hostname || target.host}`);
}
const realIp = req.connection.remoteAddress.replace(/^::ffff:/, "");
headers.push(`X-Real-IP: ${realIp}`);
const forward = req.headers["x-forwarded-for"] || "";
headers.push(`X-Forwarded-For: ${forward}${forward ? ", " : ""}${realIp}`);
proxySocket.write([
`${req.method} ${req.url} HTTP/1.1`,
...headers,
"\r\n"
].join("\r\n"));
if (head && head.length > 0) {
proxySocket.write(head);
}
socket.pipe(proxySocket);
proxySocket.pipe(socket);
});
proxySocket.on("error", () => {
clearTimeout(timeout);
socket.write("HTTP/1.1 502 Bad Gateway\r\n\r\n");
socket.destroy();
});
socket.on("error", () => {
clearTimeout(timeout);
proxySocket.destroy();
});
socket.on("close", () => {
clearTimeout(timeout);
proxySocket.destroy();
});
proxySocket.on("close", () => {
clearTimeout(timeout);
socket.destroy();
});
});
}
