【问题标题】:Binding HTTP and HTTPS traffic on the SAME port in node.js?在 node.js 的 SAME 端口上绑定 HTTP 和 HTTPS 流量?
【发布时间】:2018-11-07 08:44:01
【问题描述】:

我有一个场景,我的 node.js 应用程序位于负载平衡 HAProxy 后面,该 HAProxy 将 HTTP 和 HTTPS 流量转发到我的节点服务器上的端口 8000。

不幸的是,这让我陷入了一个棘手的境地:我需要为我的 http 和 https 服务器使用相同的端口。如果这在某种程度上更容易的话,我也会满足于仅仅将 http 重定向到 https。

但是,现在,我不得不选择 HTTP -- 或 -- HTTPS

为了包含代码...

https.createServer(api.credentials, api.server).listen(8000);
http.createServer(api.server).listen(8000); // ERR ADDR IN USE

【问题讨论】:

  • 我研究了这个;在节点中几乎不可能做到。我能够完成它的唯一方法是:1)有一个带有 Socket 侦听器的端口,检查前几个字节,然后转发到其他两个端口之一(分别处理 http 和 https),因为没有办法处理关闭现有套接字并创建一个新的 http/httpsrequest。
  • HAProxy 不能为你破解 SSL,在所有情况下都只转发 HTTP 吗?
  • @Joe 这正是我最初所做的...... HAProxy 使用 Apache 的反向代理来服务 SSL 并将 HTTP 发送到节点。但是,我需要使用 WebSockets,这意味着要摆脱 Apache,从而导致我遇到这个问题......
  • 为什么需要在同一个端口上同时提供服务?为什么不将 8000 端口用于 HTTP,将 8001 端口用于 HTTPS?
  • @KeithPalmer 这就是 HAProxy 的设置方式。我正在与 RightScale 合作,试图找到一种通过不同端口转发 HTTPS 的方法......看起来应该是可能的,但我希望在节点端有一个解决方案。

标签: node.js


【解决方案1】:

您不能将多个服务器绑定到同一个端口,但您可以打开一个 TCP 服务器并将流量代理到相关的 HTTP 实现。

httpx.js

'use strict';
let net = require('net');
let http = require('http');
let https = require('https');

exports.createServer = (opts, handler) => {

    let server = net.createServer(socket => {
        socket.once('data', buffer => {
            // Pause the socket
            socket.pause();

            // Determine if this is an HTTP(s) request
            let byte = buffer[0];

            let protocol;
            if (byte === 22) {
                protocol = 'https';
            } else if (32 < byte && byte < 127) {
                protocol = 'http';
            }

            let proxy = server[protocol];
            if (proxy) {
                // Push the buffer back onto the front of the data stream
                socket.unshift(buffer);

                // Emit the socket to the HTTP(s) server
                proxy.emit('connection', socket);
            }
            
            // As of NodeJS 10.x the socket must be 
            // resumed asynchronously or the socket
            // connection hangs, potentially crashing
            // the process. Prior to NodeJS 10.x
            // the socket may be resumed synchronously.
            process.nextTick(() => socket.resume()); 
        });
    });

    server.http = http.createServer(handler);
    server.https = https.createServer(opts, handler);
    return server;
};

example.js

'use strict';
let express = require('express');
let fs = require('fs');
let io =  require('socket.io');

let httpx = require('./httpx');

let opts = {
    key: fs.readFileSync('./server.key'),
    cert: fs.readFileSync('./server.cert')
};

let app = express();
app.use(express.static('public'));

let server = httpx.createServer(opts, app);
let ws = io(server.http);
let wss = io(server.https);
server.listen(8080, () => console.log('Server started'));

【讨论】:

    【解决方案2】:

    你不能让两个任务监听同一个端口。 HTTP 侦听默认端口 80,HTTPS 侦听默认端口 443。 您将需要管理您的 HAProxy 程序以相应地转发。

    我发现 this nifty page 建议您像这样设置配置:

    全局
      stats socket ./haproxy.stats 级别管理员
    
    前端 ft_http
        绑定:80
        模式http
        default_backend bk_http
    
    前端 ft_https
        绑定:443
        模式 tcp
        default_backend bk_https
    
    后端 bk_http
        模式http
        平衡循环
        坚持 src 表 bk_https
        默认服务器间 1s
        服务器 s1 192.168.1.1:80 检查 id 1
        服务器 s2 192.168.1.2:80 检查 id 2
    
    后端 bk_https
        模式 tcp
        平衡循环
        stick-table 类型 ip 大小 200k 过期 30m
        坚持src
        默认服务器间 1s
        服务器 s1 192.168.1.1:443 检查 id 1
        服务器 s2 192.168.1.2:443 检查 id 2

    请注意上面的配置如何将 Node.js 端口设置为 80 和 443。由于 Node.js 没有管理员权限,您可能需要编辑端口以像这样工作:

     后端 bk_http
        模式http
        平衡循环
        坚持 src 表 bk_https
        默认服务器间 1s
        服务器 s1 192.168.1.1:8000 检查 id 1
        服务器 s2 192.168.1.2:8000 检查 id 2
    
    后端 bk_https
        模式 tcp
        平衡循环
        stick-table 类型 ip 大小 200k 过期 30m
        坚持src
        默认服务器间 1s
        服务器 s1 192.168.1.1:8001 检查 id 1
        服务器 s2 192.168.1.2:8001 检查 id 2

    您还需要将 Node.js 代码更改为:

    https.createServer(api.credentials, api.server).listen(8001);
    http.createServer(api.server).listen(8000);

    我对 HAProxy 不熟悉,所以我可能会离开。

    【讨论】:

    • 这与我最终所做的非常接近。我在 HAProxy 上设置 ACL 以检测 http/https 并将 HTTP 请求重新路由到 HTTPS。
    猜你喜欢
    • 2021-09-17
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 2012-11-16
    • 2019-02-02
    • 2019-08-30
    • 2013-04-12
    相关资源
    最近更新 更多