Pull to refresh

Comments 17

Решение — все на одном порту и апгрейд https до wss.
С TSL не пробовал но HTTP -> WS socket.io так и делает.
а различать запросы как? у меня там еще и HTTP-сервер сбоку для приема команд.

честно не понимаю, можно схему словами описать?
ну в URL есть же не только адрес, порт но и путь.
в socket.io клиент стучится на http://address:port/socket.io
и просит апгрейд протокола до WS
а чем это изменит запрос подтверждения сертификата в нашем случае?

браузер молча срубит запрос, и все. или я чего не понимаю опять.

да, и по-моему есть некое недопонимание архитектуры. компонентов два.

первый — бэкенд Web UI (443)

второй — WSS Comet-сервер (4433) + HTTP сервер (8090) для внутренних запросов

и никак их на один порт не повесишь
повторюсь я не пробовал с TLS, но по идее на момент апгрейда протокола, безопасное соединение уже установлено и сертификат подтверждать не нужно.

Повесить на один порт с помощью NodeJS можно, я думаю.
Естественно для WebUI это будет прокси, точнее больше похоже на проброс порта.
Вот тут, например, обсуждается вариант. И то не самый лучший. Можно не делать редиректы, просто пайпить и все.
в socket.io клиент стучится на http://address:port/socket.io

тут я должен бы пояснить, что в javascript инициализация вида

var ws = new Websocket('http://address:port/'); 

свалится с ошибкой, потому что надо делать

var ws = new Websocket('ws://address:port/);

а последнее не стартанет из-за того, что с секурной странички открытой по https нельзя открывать подключение к несекурному узлу с незащищенным протоколом, т.е.

var ws = new Websocket('wss://address:port/');

на момент апгрейда протокола, безопасное соединение уже установлено

я так понимаю, мы все-таки про прокси? так вот смотрите, если я основную страницу открыл грубо говоря https://127.0.0.1/ и стучусь в wss://127.0.0.1/wss/, то в бэкенде код прокси вида

var proxy = httpProxy.createProxyServer({});

http.createServer(function(req, res) {
    var hostname = req.headers.host.split(":")[0];
    var pathname = url.parse(req.url).pathname;

    var options = {};

    if (pathname == '/wss/') {
        options.target = 'ws://' + httpHost + ':' + wsPort + '/';
        options.ws = true;
        proxy.ws(req, res, options);
    } else {
        options.target = 'http://' + httpHost + ':' + httpPort + '/';
        proxy.web(req, res, options);

    }

}).listen(proxyPort);

в упор не видит WS запроса, потому что это все-таки не HTTP запрос, я так понимаю:

    GET /demo HTTP/1.1
    Upgrade: WebSocket
    Connection: Upgrade
    Sec-WebSocket-Key2: 4 @1 46546xW%0l 1 5
    Host: example.com
    Sec-WebSocket-Key1: 12998 5 Y3 1 .P00
    Origin: http://example.com
    WebSocket-Protocol: sample

я об этом вобщем и написал в статье…
т.е. callback на http.createServer не вызывается для этого запроса?
а что же происходит с соединением?
вообще это явно HTTP запрос, он не может его просто сбрасывать.
если не может обработать должен выдать код ошибки.
именно.

http-сервер его просто не обрабатывает (не ловит) почему-то.
Да это так и должно быть — смотри мой коммент ниже со ссылкой на доки ноды. Нужно слушать событие 'upgrade'.
Пришлось пойти посмотреть в исходники engine.io, чтоб понять, что он делает. Потому что там это точно работает.
Еще для информации

Event: 'upgrade'#

function (request, socket, head) { }

Emitted each time a client requests a http upgrade. If this event isn't listened for, then clients requesting an upgrade will have their connections closed.
я не совсем корректный пример кода привел в прокси-сервере, не до конца инвестигировал. у нас все-таки https-сервер, завтра попробую еще раз помучать тему прокси на Node.JS.

я видимо с http еще плюнул на эту идею и не стал дальше смотреть.
бинго! вариант с прокси на Node.JS все-таки получился! надо было действительно проксировать на upgrade, а не на непосредственно запрос, спасибо.

а здесь принято поправить пост и дописать некий Update про третий вариант с кодом?

вот код прокси, если интересно:

app.js

var
    http = require('https'),
    https = require('https'),
    url = require('url'),
    httpProxy = require('http-proxy'),
    fs = require('fs');

var config = require('./config/config.json');

var proxy = httpProxy.createProxyServer({});

function proxyHttpResponse(req, res) {
    var hostname = req.headers.host.split(":")[0];
    var pathname = url.parse(req.url).pathname;

    try {
        var options = {
            target: 'http://' + config.http.host + ':' + config.http.port + '/'
        };
        proxy.web(req, res, options);
    } catch (e) {
        console.log('Error: ' + e.message);
    }
}

function proxyWebsocketResponse(req, res) {
    var hostname = req.headers.host.split(":")[0];
    var pathname = url.parse(req.url).pathname;

    if (pathname === '/ws/') {
        try {
            var options = {
                target: 'ws://' + config.websocket.host + ':' + config.websocket.port + '/',
                ws: true
            };
            proxy.ws(req, res, options);
        } catch (e) {
            console.log('Error: ' + e.message);
        }
    } else {
        res.statusCode = 501;
        res.end('Not Implemented');
    }
}


if (config.server.ssl) {
    var options = {
        port: config.server.sslPort,
        key: fs.readFileSync(config.server.sslKey),
        cert: fs.readFileSync(config.server.sslCert)
    };

    var server = https.createServer(options, proxyHttpResponse).listen(config.server.sslPort, function () {
        console.log('Proxy server (SSL) started on *:' + config.server.sslPort);
    });
} else {
    var server = http.createServer(proxyHttpResponse).listen(config.server.port, function () {
        console.log('Proxy server started on *:' + config.server.port);
    });
}

server.addListener('upgrade', proxyWebsocketResponse);

config.json

{
    "debug": true,

    "server": {
        "ssl": true,
        "port": 80,
        "sslPort": 443,
        "sslKey"  : "cert/server.key",
        "sslCert" : "cert/server.pem"
    },

    "http": {
        "port": 8080,
        "host": "127.0.0.1"
    },

    "websocket": {
        "port": 8095,
        "host": "127.0.0.1"
    }
}
Если использование внутрикорпаротивное, то просто ставим всем клиентам сертификат центра сертификации (CA), которым подписан ключ веб-сервера и все будет работать «из коробки»
кстати да. а сертификат собственного такого же CA прокатит в этом случае?
Так все-таки, в чем была проблема с nginx под виндой?
я его года четыре назад пробовал — падал постоянно и глючило его. может конечно что и изменилось.
Sign up to leave a comment.

Articles