自定义HTTPS服务器-WebSocket不起作用

时间:2019-08-17 14:58:58

标签: node.js https websocket server proxy

我有一个程序可以通过http(没有ssl)提供页面。我想确保这一点。因此,我正在编写一个nodejs程序以用作代理服务器。

nodejs程序(代理)将接受来自客户端的所有请求,将请求重复发送到服务器,接收响应并将其发回客户端。

除websocets之外,其他所有功能都可以!

我可以看到初始请求和响应的行为符合预期:

请求:

GET /wstest HTTP/1.1 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Accept: qszv9wJR+ldyUuHgwOZOsv/2rQw= 
Date: Sat, 17 Aug 2019 14

响应:

HTTP/1.1 101 Switching Protocols 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Accept: qszv9wJR+ldyUuHgwOZOsv/2rQw= 
Date: Sat, 17 Aug 2019 14:17:13 GMT

然后连接保持打开状态,并定期从客户端收到一些消息:8A 00(十六进制)

Chrome 76.0.3809.100,Chrome Canary 78.0.3886.0和FireFox的行为也有所不同,我不确定如何处理这些消息。

Canary从服务器获取消息响应,但Chrome没有。在所有浏览器中,ws连接状态始终处于挂起状态。


    const fs = require("fs");
    const https = require("https");
    const net = require('net');

    const source_hostname = "127.0.0.1";
    const source_port = 80;
    const destin_hostname = "127.0.0.1";
    const destin_port = 8443;

    const proxy_opt = {
        pfx: fs.readFileSync("ssl/cert.pfx"),
        passphrase: "###################"
    };

    const proxy = https.createServer(proxy_opt, (req, res) => { serve(req, res); });

    proxy.listen(destin_port, destin_hostname, () => {
        console.log(`Listening on: https://${destin_hostname}:${destin_port}/`);
    });

    const serve = (req, res) => {
        let socket = new net.Socket();

        let isFirst = true;
        socket.on("data", data => {
            let neck = findNeck(data);
            let chunk_stop = data.length - 1;
            let resArrayHead = data.subarray(0, neck).toString().trim().split("\r\n");
            let statusCode = parseInt(resArrayHead[0].split(" ")[1]) || 400;

            let headers = {};
            //headers["Connection"] = "close";
            for (let i = 1; i < resArrayHead.length; i++) {
                let s = resArrayHead[i].split(":");
                if (s.length == 1) continue;
                headers[s[0].trim()] = s[1].trim();
            }

            if (headers["Transfer-Encoding"] == "chunked") { //handle chunked data
                let precrop = neck;

                for (let i=neck+1; i<Math.min(data.length, neck+8); i++)
                    if (data[i - 1] == 13 && data[i] == 10) {
                        neck = i + 1;
                        break;
                    }

                let chunk_size=parseInt(data.subarray(precrop,neck).toString().trim(), 16);
                chunk_stop = neck + chunk_size;

                if (data[chunk_stop-4] == 48 &&
                    data[chunk_stop-3] == 13 &&
                    data[chunk_stop-2] == 10 &&
                    data[chunk_stop-1] == 13 &&
                    data[chunk_stop] == 10)
                    chunk_stop -= 5;
            }

            if (req.url == "/wstest") {
                console.log(data[0], data[1], data[2], data[3]);
                //console.log(" > ", headers);
                //console.log(" < ", data);
            }

            if (isFirst) {
                res.writeHead(statusCode, headers);
                res.write(data.subarray(neck, chunk_stop));
            } else
                res.write(data);

            isFirst = false;
        });

        socket.on("error", err => console.log("err: ", req.url, err));

        socket.on("end", () => res.end());

        req.on("data", chunk => {
            socket.write(chunk);
        });

        req.on("end", () => socket.end());

        let reqStringHead = "";
        for (let key in req.headers)
            reqStringHead += key + ": " + req.headers[key] + "\r\n";

        reqStringHead += "X-Forwarded-For: " + source_hostname + "\r\n";

        socket.connect(source_port, source_hostname);
        socket.write(`${req.method} ${req.url} HTTP/1.1\r\n${reqStringHead}\r\n`);
    };

    const findNeck = (data) => { //Finds the point where head and body separates.
        if (data == null && (data.length || 0) < 4) return 0;

        let neck = 0;
        for (neck = 3; neck < Math.min(data.length, 768); neck++)
            if (data[neck - 3] == 13 &&
                data[neck - 2] == 10 &&
                data[neck - 1] == 13 &&
                data[neck] == 10) 
                return neck;

        return 0;
    };

1 个答案:

答案 0 :(得分:0)

感谢jfriend00,我使用了nginx。

这是我的配置文件:

worker_processes 2;

events {
    worker_connections  1024;
}

http {
    sendfile on;

    #https proxy server
    server {
        listen       443 ssl;
        server_name  localhost;
        ssl_certificate      ../ssl/cert.crt;
        ssl_certificate_key  ../ssl/private.key;

        location / {
            proxy_pass http://127.0.0.1:80/;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

        location /ws/ {
            proxy_pass http://127.0.0.1:80/$request_uri;
            proxy_http_version 1.1;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }

    }
}