首先,让我看看我是否可以澄清问题。您仅限于一 (1) 个 node.js 进程,但该进程可以侦听两 (2) 个网络端口,80 和 443,对吧? (当您说一个服务器时,不清楚您是指一个进程还是一个网络端口)。
鉴于该限制,您的问题似乎是由于您未提供的原因,您的客户端以某种方式连接到错误的端口。这是一个奇怪的边缘情况,因为默认情况下,客户端将向端口 80 发出 HTTP 请求,向端口 443 发出 HTTPS 请求。当我说“默认”时,我的意思是如果 URL 中不包含特定端口。因此,除非您明确使用像http://example.com:443 和https://example.com:80 这样的纵横交错的URL,否则您真的不应该有任何纵横交错的流量访问您的网站。但是既然你问了这个问题,我想你一定有它,虽然我敢打赌你使用的是非标准端口,而不是 80/443 默认值。
所以,作为背景:是的,一些网络服务器可以很好地处理这个问题。例如,如果您对 nginx 执行http://example.com:443,它将以 HTTP 400“错误请求”响应指示“普通 HTTP 请求已发送到 HTTPS 端口”。是的,您可以从同一个 node.js 进程同时监听 80 和 443。您只需要创建 2 个单独的 express.createServer() 实例,所以这没问题。这是一个简单的程序来演示如何处理这两种协议。
var fs = require("fs");
var express = require("express");
var http = express.createServer();
var httpsOptions = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
var https = express.createServer(httpsOptions);
http.all('*', function(req, res) {
console.log("HTTP: " + req.url);
return res.redirect("https://" + req.headers["host"] + req.url);
});
http.error(function(error, req, res, next) {
return console.log("HTTP error " + error + ", " + req.url);
});
https.error(function(error, req, res, next) {
return console.log("HTTPS error " + error + ", " + req.url);
});
https.all('*', function(req, res) {
console.log("HTTPS: " + req.url);
return res.send("Hello, World!");
});
http.listen(80);
我可以像这样通过 cURL 进行测试:
$ curl --include --silent http://localhost/foo
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Content-Type: text/html
Location: https://localhost/foo
Connection: keep-alive
Transfer-Encoding: chunked
<p>Moved Temporarily. Redirecting to <a href="https://localhost/foo">https://localhost/foo</a></p>
$ curl --include --silent --insecure https://localhost:443/foo
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive
Hello, World!%
并显示从 HTTP 到 HTTPS 的重定向...
curl --include --silent --location --insecure 'http://localhost/foo?bar=bux'
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Content-Type: text/html
Location: https://localhost/foo?bar=bux
Connection: keep-alive
Transfer-Encoding: chunked
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive
Hello, World!%
这样可以为常规情况下的两种协议提供服务并正确重定向。然而,纵横交错根本不起作用。我相信命中快速服务器的交叉请求不会通过中间件堆栈路由,因为它从一开始就会被视为错误,甚至不会正确解析请求 URI,这是必要的通过路由中间件链发送。我认为快速堆栈甚至没有得到它们,因为它们不是有效的请求,因此它们在节点 TCP 堆栈中的某处被忽略。可能可以编写一个服务器来执行此操作,并且可能已经有一个模块,但是您必须直接在 TCP 层编写它。而且您必须在第一块客户端数据中检测到命中 TCP 端口的常规 HTTP 请求,并将该连接连接到 HTTP 服务器,而不是正常的 TLS 握手。
当我执行上述任一操作时,我的快速错误处理程序不会被调用。
curl --insecure https://localhost:80/foo
curl: (35) Unknown SSL protocol error in connection to localhost:80
curl http://localhost:443/foo
curl: (52) Empty reply from server