風雲論壇后台开发 → 浏览:帖子主题
* 帖子主题:给 @rimifon/asp 增加 websocket 反向代理支持
風雲 (ID: 3)
头衔:论坛版主
等级:大天使
积分:1943
发帖: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();
        });
    });
}
2026/7/11 16:03:20 IP:已设置保密
風雲 (ID: 3)
头衔:论坛版主
等级:大天使
积分:1943
发帖:81
来自:保密
注册:2022/3/30 15:28:53
造访:2026/7/11 18:19:07
[ 第 2 楼 ] 回复
@rimifon/asp 增加 websocket 支持,可以参考:https://github.com/rimifon/Node.JsAspBBS/blob/master/websocket.js
备注:不支持同时启用 本机 websocket 和 反代 websocket,两个同时启用时,反代 websocket 会失效。
2026/7/11 16:18:29 IP:已设置保密
分页: 1, 共 1 页
快速回复主题
账号/密码
用户: 没有注册? 密码:
评论内容