Node.js 支持 HTTP/2,但不是通过 http
模块,而是通过 http2
模块来实现。从 Node.js 8.4.0 开始,该模块已被包含在核心库中,所以你不需要额外的依赖就可以使用它。
以下是一个简单的 HTTP/2 服务器示例,需要注意的是 HTTP/2 通常使用 TLS,因此需要 SSL 证书和密钥:
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('path_to_private_key.pem'),
cert: fs.readFileSync('path_to_certificate.pem')
});
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8443);
在上述示例中,你需要为 path_to_private_key.pem
和 path_to_certificate.pem
提供正确的路径,指向你的私钥和证书文件。你可以使用 Let’s Encrypt 获取免费的证书,或者为本地开发使用 openssl 创建自签名证书。
此外,建议在生产环境中不要直接使用 Node.js 提供的 HTTP/2 实现,而是使用反向代理,如 NGINX 或 Caddy,来处理 HTTP/2 连接,然后将请求代理到 Node.js 服务器。这种方法通常更为稳定且具有更好的性能。
使用 openssl
为本地开发创建自签名证书是一个常见的做法,尤其是当你需要在本地环境中测试 HTTPS 或 HTTP/2 功能时。以下是如何使用 openssl
创建自签名证书的步骤:
- 生成私钥:
这将会生成一个 RSA 2048 位的私钥 (server.key
)。openssl genrsa -out server.key 2048
生成证书签名请求 (CSR):
这将基于你的私钥生成一个 CSR。当被询问 “Common Name (e.g., server FQDN or YOUR name)” 时,输入你的服务器的域名或localhost
(如果你只是本地测试)。openssl req -new -key server.key -out server.csr -config ./openssl.cnf
生成自签名证书:
使用私钥和 CSR,这将生成一个有效期为 365 天的证书 (server.crt
)。openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
现在,你应该有了以下的文件:
server.key
: 你的私钥。server.crt
: 你的自签名证书。
使用这些文件,你可以在各种应用程序和工具中设置 HTTPS,包括 Node.js。
注意:由于这是一个自签名证书,所以当你在浏览器中尝试访问使用该证书的站点时,浏览器会警告你此证书不被信任。在本地开发中,这通常是可以接受的,但请确保不要在生产环境中使用自签名证书。
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('./server.key'),
cert: fs.readFileSync('./server.crt')
});
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8888);
你可以使用 Express 与 HTTP/2 一起工作,但是Express本身不直接支持HTTP/2。你需要使用http2
模块或其他库,如spdy
,来与Express一起实现HTTP/2支持。
下面是一个使用spdy
与Express一起创建HTTP/2服务器的简单示例:
首先,你需要安装所需的模块:
npm install express spdy
然后,你可以编写如下的代码:
const express = require('express');
const spdy = require('spdy');
const fs = require('fs');
const path = require('path');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, HTTP/2!');
});
const options = {
key: fs.readFileSync(path.join(__dirname, './server.key')),
cert: fs.readFileSync(path.join(__dirname, './server.crt'))
};
spdy
.createServer(options, app)
.listen(8888, () => {
console.log('HTTP/2 server running on https://localhost:8888/');
});
请确保你的server.key
和server.crt
文件路径是正确的。
与之前的HTTP/2示例一样,因为你使用的是自签名证书,所以当你尝试访问https://localhost:8888/
时,浏览器可能会给出安全警告。你可以选择继续前往。
另外,要完全利用HTTP/2的优势,如服务器推送,你可能需要进一步的配置和代码调整。但上面的示例是一个快速开始,用于设置Express与HTTP/2的基本交互。
服务端支持 http2,那么客户端是否需要修改呢?
不需要。HTTP/2 是设计为对于终端用户是透明的。这意味着,如果服务端支持 HTTP/2,客户端(例如 Web 浏览器)会自动使用 HTTP/2 进行通信,前提是该客户端也支持 HTTP/2。对于 Web 开发者和用户而言,他们无需进行任何特殊的修改或设置。
但是,有几点值得注意:
- 客户端支持情况:大部分现代浏览器都已经支持 HTTP/2,但是确保用户的浏览器是更新的版本,特别是如果他们使用的是较旧的浏览器或者是某些特定的移动浏览器。
- 协议协商:当客户端与支持 HTTP/2 的服务器通信时,它们会使用一个叫做 ALPN (Application-Layer Protocol Negotiation) 的技术来决定是否使用 HTTP/2 还是回退到 HTTP/1.x。
- 安全性:虽然 HTTP/2 技术上支持明文(非加密)的连接,但大多数现代浏览器都要求 HTTP/2 连接必须是加密的。因此,在大多数实际场景中,要使用 HTTP/2,你需要使用 HTTPS。
- 手动测试:如果你想测试或调试 HTTP/2 连接,你可能需要使用特定的工具或浏览器配置。
- 优化:虽然不需要在客户端进行修改以支持 HTTP/2,但你可能想要考虑优化你的 Web 应用或站点来更好地利用 HTTP/2 的特性,如请求多路复用、服务器推送等。
总的来说,从客户端的角度看,迁移到 HTTP/2 是透明的,但从网站或 Web 应用的优化和性能提升的角度看,可能需要进行一些工作。
客户端发送的请求报文的请求头写的协议版本是 HTTP/1.1,也可以使用 HTTP/2 的服务?
是的,客户端可以发送一个协议版本为 HTTP/1.1 的请求,但仍然使用 HTTP/2 与服务器进行通信,这归功于一个过程叫做协议协商。
当一个支持 HTTP/2 的客户端与服务器建立连接时,它们会使用一个称为 ALPN (Application-Layer Protocol Negotiation) 的技术来确定使用哪个版本的 HTTP 协议。如果客户端和服务器都支持 HTTP/2,那么它们会选择使用 HTTP/2。此后,客户端和服务器间的所有通信都会使用 HTTP/2 协议,即使原始请求中的协议版本是 HTTP/1.1。
这就是为什么在使用工具或浏览器访问支持 HTTP/2 的服务器时,你可能会看到请求头中显示的协议版本是 HTTP/1.1,但实际上数据交换是在 HTTP/2 协议下完成的。
这种设计使得 HTTP/2 的引入和部署变得平滑,不需要客户端或服务器做大的改变。只要双方都支持 HTTP/2,并正确地配置了 ALPN,就可以自动使用新协议。
生成 .crt
和 .key
文件的详细步骤
要生成自签名证书和关键字,您可以使用openssl
工具。以下是为localhost
生成一个带有适当SAN(Subject Alternative Name)的证书的步骤:
- 首先,打开一个命令行窗口。
- 创建一个名为
openssl.cnf
的配置文件,并在其中写入以下内容:
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = Some State
L = Some City
O = Company Name
OU = Organizational Unit
CN = localhost
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
保存此文件。
- 使用以下命令生成证书和私钥:
openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -config openssl.cnf -keyout server.key -out server.crt
这将生成一个名为server.key
的私钥文件和一个名为server.crt
的证书文件。
- 使用这两个新生成的文件在您的应用程序中。
请注意,此自签名证书仅用于开发和测试目的。如果您要在生产环境中使用证书,建议从受信任的证书颁发机构(CA)购买一个正式的证书。