源代码: lib/http2.js
http2 模块提供了 HTTP/2 协议的实现。
可以使用以下方式访问它:
const http2 = require('http2');
核心 API 提供了低层的接口,专门围绕支持 HTTP/2 协议功能而设计。 它专为与现有 HTTP/1 模块 API 兼容而设计。 但是,兼容性 API是。
与 http API 相比,http2 核心 API 在客户端和服务器之间更加对称。
例如,大多数事件,如 'error'、'connect' 和 'stream',可以由客户端代码或服务器端代码触发。
以下说明了使用核心 API 的简单 HTTP/2 服务器。
由于没有已知的浏览器支持未加密的 HTTP/2,所以在与浏览器客户端通信时必须使用 http2.createSecureServer()。
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, headers) => {
// 流是双工的
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8443);
要为此示例生成证书和密钥,则运行:
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
-keyout localhost-privkey.pem -out localhost-cert.pem
以下说明了 HTTP/2 客户端:
const http2 = require('http2');
const fs = require('fs');
const client = http2.connect('https://localhost:8443', {
ca: fs.readFileSync('localhost-cert.pem')
});
client.on('error', (err) => console.error(err));
const req = client.request({ ':path': '/' });
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
console.log(`\n${data}`);
client.close();
});
req.end();
Http2Session 类#http2.Http2Session 类的实例表示 HTTP/2 客户端和服务器之间的活动通信会话。
此类的实例_不_旨在由用户代码直接构造。
每个 Http2Session 实例将表现出略有不同的行为,具体取决于它是作为服务器还是客户端运行。
http2session.type 属性可用于确定 Http2Session 的运行模式。
在服务器端,用户代码很少有机会直接使用 Http2Session 对象,大多数操作通常是通过与 Http2Server 或 Http2Stream 对象的交互来执行的。
用户代码不会直接创建 Http2Session 实例。
服务器端 Http2Session 实例是在接收到新的 HTTP/2 连接时由 Http2Server 实例创建的。
客户端 Http2Session 实例是使用 http2.connect() 方法创建的。
每个 Http2Session 实例在创建时都与 net.Socket 或 tls.TLSSocket 关联。
当 Socket 或 Http2Session 被摧毁时,两者都会被摧毁。
由于 HTTP/2 协议规定的特定序列化和处理要求,不建议用户代码从绑定到 Http2Session 的 Socket 实例读取数据或向其写入数据。
这样做会使 HTTP/2 会话进入不确定状态,导致会话和套接字变得不可用。
一旦将 Socket 绑定到 Http2Session,用户代码应仅依赖于 Http2Session 的 API。
'close' 事件#'close' 事件在 Http2Session 被销毁后触发。
其监听器不需要任何参数。
'connect' 事件#session <Http2Session>socket <net.Socket>一旦 Http2Session 成功连接到远程对等方并且通信可以开始,则会触发 'connect' 事件。
用户代码通常不会直接监听此事件。
'error' 事件#error <Error>'error' 事件在处理 Http2Session 期间发生错误时触发。
'frameError' 事件#当尝试在会话上发送帧时发生错误时会触发 'frameError' 事件。
如果无法发送的帧与特定的 Http2Stream 相关联,则会尝试在 Http2Stream 上触发 'frameError' 事件。
如果 'frameError' 事件与流相关联,则该流将在 'frameError' 事件之后立即关闭并销毁。
如果事件与流无关,则 Http2Session 将在 'frameError' 事件之后立即关闭。
'goaway' 事件#errorCode <number> GOAWAY 帧中指定的 HTTP/2 错误代码。lastStreamID <number> 远程对等方成功处理的最后一个流的 ID(如果未指定 ID,则为 0)。opaqueData <Buffer> 如果 GOAWAY 帧中包含其他不透明数据,则将传入包含该数据的 Buffer 实例。接收到 GOAWAY 帧时触发 'goaway' 事件。
'goaway' 事件触发时,Http2Session 实例会自动关闭。
'localSettings' 事件#settings <HTTP/2 Settings Object> 接收到了 SETTINGS 帧的副本。当接收到确认 SETTINGS 帧时触发 'localSettings' 事件。
当使用 http2session.settings() 提交新的设置时,修改后的设置在 'localSettings' 事件触发后才会生效。
session.settings({ enablePush: false });
session.on('localSettings', (settings) => {
/* 使用新的设置 */
});
'ping' 事件#payload <Buffer> PING 帧 8 字节有效载荷每当从连接的对等方接收到 PING 帧时,则会触发 'ping' 事件。
'remoteSettings' 事件#settings <HTTP/2 Settings Object> 接收到了 SETTINGS 帧的副本。当从连接的对等方接收到新的 SETTINGS 帧时,则会触发 'remoteSettings' 事件。
session.on('remoteSettings', (settings) => {
/* 使用新的设置 */
});
'stream' 事件#stream <Http2Stream> 对流的引用headers <HTTP/2 Headers Object> 描述标头的对象flags <number> 相关的数字标志rawHeaders <Array> 包含原始标头名称后跟它们各自值的数组。创建新的 Http2Stream 时会触发 'stream' 事件。
const http2 = require('http2');
session.on('stream', (stream, headers, flags) => {
const method = headers[':method'];
const path = headers[':path'];
// ...
stream.respond({
':status': 200,
'content-type': 'text/plain; charset=utf-8'
});
stream.write('hello ');
stream.end('world');
});
在服务器端,用户代码通常不会直接监听此事件,而是为分别由 http2.createServer() 和 http2.createSecureServer() 返回的 net.Server 或 tls.Server 实例触发的 'stream' 事件注册句柄,如下例所示:
const http2 = require('http2');
// 创建未加密的 HTTP/2 服务器
const server = http2.createServer();
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
stream.on('error', (error) => console.error(error));
stream.end('<h1>Hello World</h1>');
});
server.listen(80);
即使 HTTP/2 流和网络套接字不是 1:1 对应,网络错误也会破坏每个单独的流,必须在流级别上处理,如上所示。
'timeout' 事件#使用 http2session.setTimeout() 方法为此 Http2Session 设置超时时间后,如果在配置的毫秒数后 Http2Session 上没有活动,则触发 'timeout' 事件。
其监听器不需要任何参数。
session.setTimeout(2000);
session.on('timeout', () => { /* .. */ });
http2session.alpnProtocol#如果 Http2Session 尚未连接到套接字,则值为 undefined,如果 Http2Session 未连接到 TLSSocket,则值为 h2c,或者将返回已连接的 TLSSocket 自己的 alpnProtocol 属性的值。
http2session.close([callback])#callback <Function>正常地关闭 Http2Session,允许任何现有的流自行完成并防止创建新的 Http2Stream 实例。
一旦关闭,如果没有打开的 Http2Stream 实例,则 http2session.destroy() _可能_会被调用。
如果指定,则 callback 函数将注册为 'close' 事件的句柄。
http2session.closed#如果此 Http2Session 实例已关闭,则为 true,否则为 false。
http2session.connecting#如果此 Http2Session 实例仍在连接,则将是 true,在触发 connect 事件和/或调用 http2.connect 回调之前将设置为 false。
http2session.destroy([error][, code])#error <Error> 如果 Http2Session 因错误而被销毁,则为 Error 对象。code <number> 要在最终 GOAWAY 帧中发送的 HTTP/2 错误代码。
如果未指定,且 error 未未定义,则默认为 INTERNAL_ERROR,否则默认为 NO_ERROR。立即终止 Http2Session 和相关联的 net.Socket 或 tls.TLSSocket。
一旦销毁,则 Http2Session 将触发 'close' 事件。
如果 error 未定义,则将在 'close' 事件之前立即触发 'error' 事件。
如果有任何剩余的与 Http2Session 关联的开放 Http2Streams,则它们也会被销毁。
http2session.destroyed#如果此 Http2Session 实例已被销毁且不能再使用,则为 true,否则为 false。
http2session.encrypted#如果 Http2Session 会话套接字尚未连接,则值为 undefined,如果 Http2Session 与 TLSSocket 连接,则值为 true,如果 Http2Session 连接到任何其他类型的套接字或流,则值为 false。
http2session.goaway([code[, lastStreamID[, opaqueData]]])#code <number> HTTP/2 错误代码lastStreamID <number> 最后处理的 Http2Stream 的数字 IDopaqueData <Buffer> | <TypedArray> | <DataView> TypedArray 或 DataView 实例,包含要在 GOAWAY 帧中携带的附加数据。将 GOAWAY 帧传输到连接的对等方_而不_关闭 Http2Session。
http2session.localSettings#描述此 Http2Session 当前本地设置的无原型对象。
本地设置是本地的此 Http2Session 实例。
http2session.originSet#如果 Http2Session 连接到 TLSSocket,则 originSet 属性将返回 Array 的起源,Http2Session 可能被认为是权威的。
originSet 属性仅在使用安全 TLS 连接时可用。
http2session.pendingSettingsAck#指示 Http2Session 当前是否正在等待已发送的 SETTINGS 帧的确认。
调用 http2session.settings() 方法后会是 true。
一旦所有发送的 SETTINGS 帧都被确认,将是 false。
http2session.ping([payload, ]callback)#payload <Buffer> | <TypedArray> | <DataView> 可选的 ping 负载。callback <Function>向连接的 HTTP/2 对等方发送 PING 帧。
必须提供 callback 函数。
如果发送了 PING,则该方法将返回 true,否则返回 false。
未完成的(未确认的)ping 的最大数量由 maxOutstandingPings 配置选项决定。
默认最大值为 10。
如果提供,则 payload 必须是 Buffer、TypedArray 或 DataView,其中包含 8 个字节的数据,这些数据将与 PING 一起传输并与 ping 确认一起返回。
回调将使用三个参数调用:一个错误参数(如果 PING 被成功确认,则它将是 null),一个 duration 参数(报告自发送 ping 和收到确认以来经过的毫秒数),以及一个 Buffer(包含 8 字节 PING 有效载荷)。
session.ping(Buffer.from('abcdefgh'), (err, duration, payload) => {
if (!err) {
console.log(`Ping acknowledged in ${duration} milliseconds`);
console.log(`With payload '${payload.toString()}'`);
}
});
如果未指定 payload 参数,则默认负载将是标记 PING 持续时间开始的 64 位时间戳(小端)。
http2session.ref()#在此 Http2Session 实例的底层 net.Socket 上调用 ref()。
http2session.remoteSettings#描述此 Http2Session 当前远程设置的无原型对象。
远程设置由连接的 HTTP/2 对等方设置。
http2session.setLocalWindowSize(windowSize)#windowSize <number>设置本地端点的窗口大小。
windowSize 是要设置的总窗口大小,而不是增量。
const http2 = require('http2');
const server = http2.createServer();
const expectedWindowSize = 2 ** 20;
server.on('connect', (session) => {
// 将本地窗口大小设置为 2 ** 20
session.setLocalWindowSize(expectedWindowSize);
});
http2session.setTimeout(msecs, callback)#msecs <number>callback <Function>用于设置 msecs 毫秒后 Http2Session 上没有活动时调用的回调函数。
给定的 callback 已注册为 'timeout' 事件的监听器。
http2session.socket#返回 Proxy 对象,它充当 net.Socket(或 tls.TLSSocket),但将可用方法限制为可安全使用 HTTP/2 的方法。
destroy、emit、end、pause、read、resume、以及 write 将抛出错误代码为 ERR_HTTP2_NO_SOCKET_MANIPULATION。
有关详细信息,请参阅 Http2Session 和套接字。
将在此 Http2Session 上调用 setTimeout 方法。
所有其他交互将直接路由到套接字。
http2session.state#提供有关 Http2Session 当前状态的其他信息。
effectiveLocalWindowSize <number> Http2Session 的当前本地(接收)流控制窗口大小。effectiveRecvDataLength <number> 自上次流控制 WINDOW_UPDATE 以来已接收的当前字节数。nextStreamID <number> 下一次此 Http2Session 创建新 Http2Stream 时要使用的数字标识符。localWindowSize <number> 远程对等方在不接收 WINDOW_UPDATE 的情况下可以发送的字节数。lastProcStreamID <number> 最近收到 HEADERS 或 DATA 帧的 Http2Stream 的数字 ID。remoteWindowSize <number> 此 Http2Session 在不接收 WINDOW_UPDATE 的情况下可以发送的字节数。outboundQueueSize <number> 当前在此 Http2Session 的出站队列中的帧数。deflateDynamicTableSize <number> 出站标头压缩状态表的当前大小(以字节为单位)。inflateDynamicTableSize <number> 入站标头压缩状态表的当前大小(以字节为单位)。描述当前 Http2Session 状态的对象。
http2session.settings([settings][, callback])#settings <HTTP/2 Settings Object>callback <Function> 一旦会话连接或会话已连接时立即调用的回调。
err <Error> | <null>settings <HTTP/2 Settings Object> 更新后的 settings 对象。duration <integer>更新此 Http2Session 的当前本地设置并向连接的 HTTP/2 对等方发送新的 SETTINGS 帧。
一旦调用,当会话等待远程对等方确认新设置时,http2session.pendingSettingsAck 属性将为 true。
在收到 SETTINGS 确认并触发 'localSettings' 事件之前,新设置不会生效。
可以在确认未决时发送多个 SETTINGS 帧。
http2session.type#如果此 Http2Session 实例是服务器,则 http2session.type 将等于 http2.constants.NGHTTP2_SESSION_SERVER,如果该实例是客户端,则 http2.constants.NGHTTP2_SESSION_CLIENT 将等于。
http2session.unref()#在此 Http2Session 实例的底层 net.Socket 上调用 unref()。
ServerHttp2Session 类#serverhttp2session.altsvc(alt, originOrStream)#alt <string> RFC 7838 定义的替代服务配置的描述。originOrStream <number> | <string> | <URL> | <Object> 指定来源的 URL 字符串(或具有 origin 属性的 Object)或由 http2stream.id 属性给出的活动 Http2Stream 的数字标识符。向连接的客户端提交 ALTSVC 帧(由 RFC 7838 定义)。
const http2 = require('http2');
const server = http2.createServer();
server.on('session', (session) => {
// 为源 https://example.org:80 设置 altsvc
session.altsvc('h2=":8000"', 'https://example.org:80');
});
server.on('stream', (stream) => {
// 为特定流设置 altsvc
stream.session.altsvc('h2=":8000"', stream.id);
});
发送带有特定流 ID 的 ALTSVC 帧表示备用服务与给定 Http2Stream 的来源相关联。
alt 和原点字符串_必须_只包含 ASCII 字节,并且严格解释为 ASCII 字节序列。
可以传入特殊值 'clear' 以清除给定域的任何先前设置的替代服务。
当为 originOrStream 参数传入字符串时,则它将被解析为 URL 并导出来源。
例如,HTTP URL 'https://example.org/foo/bar' 的来源是 ASCII 字符串 'https://example.org'。
如果给定的字符串无法解析为 URL,或者无法导出有效的来源,则会抛出错误。
URL 对象,或任何具有 origin 属性的对象,都可以作为 originOrStream 传入,在这种情况下,将使用 origin 属性的值。
origin 属性的值_必须_是正确序列化的 ASCII 源。
alt 参数的格式由 RFC 7838 严格定义为 ASCII 字符串,其中包含与特定主机和端口相关联的"替代"协议的逗号分隔列表。
例如,值 'h2="example.org:81"' 表示 HTTP/2 协议在主机 'example.org' 上的 TCP/IP 端口 81 上可用。
主机和端口_必须_包含在引号 (") 字符内。
可以指定多个备选方案,例如:'h2="example.org:81", h2=":82"'。
协议标识符(示例中的 'h2')可以是任何有效的 ALPN 协议 ID。
这些值的语法未经 Node.js 实现验证,而是按照用户提供的或从对等方接收的方式传入。
serverhttp2session.origin(...origins)#向连接的客户端提交 ORIGIN 帧(由 RFC 8336 定义),以通告服务器能够为其提供权威响应的源集。
const http2 = require('http2');
const options = getSecureOptionsSomehow();
const server = http2.createSecureServer(options);
server.on('stream', (stream) => {
stream.respond();
stream.end('ok');
});
server.on('session', (session) => {
session.origin('https://example.com', 'https://example.org');
});
当字符串作为 origin 传入时,则它会被解析为 URL 并导出来源。
例如,HTTP URL 'https://example.org/foo/bar' 的来源是 ASCII 字符串 'https://example.org'。
如果给定的字符串无法解析为 URL,或者无法导出有效的来源,则会抛出错误。
URL 对象,或任何具有 origin 属性的对象,都可以作为 origin 传入,在这种情况下,将使用 origin 属性的值。
origin 属性的值_必须_是正确序列化的 ASCII 源。
或者,在使用 http2.createSecureServer() 方法创建新的 HTTP/2 服务器时可以使用 origins 选项:
const http2 = require('http2');
const options = getSecureOptionsSomehow();
options.origins = ['https://example.com', 'https://example.org'];
const server = http2.createSecureServer(options);
server.on('stream', (stream) => {
stream.respond();
stream.end('ok');
});
ClientHttp2Session 类#'altsvc' 事件#每当客户端接收到 ALTSVC 帧时,则会触发 'altsvc' 事件。
事件使用 ALTSVC 值、来源和流 ID 触发。
如果在 ALTSVC 帧中没有提供 origin,则 origin 将是空字符串。
const http2 = require('http2');
const client = http2.connect('https://example.org');
client.on('altsvc', (alt, origin, streamId) => {
console.log(alt);
console.log(origin);
console.log(streamId);
});
'origin' 事件#origins <string[]>每当客户端接收到 ORIGIN 帧时,则会触发 'origin' 事件。
该事件使用 origin 字符串的数组触发。
http2session.originSet 将被更新以包含接收到的来源。
const http2 = require('http2');
const client = http2.connect('https://example.org');
client.on('origin', (origins) => {
for (let n = 0; n < origins.length; n++)
console.log(origins[n]);
});
只有在使用安全 TLS 连接时才会触发 'origin' 事件。
clienthttp2session.request(headers[, options])#headers <HTTP/2 Headers Object>
options <Object>
endStream <boolean> 如果 Http2Stream _可写_端最初应该关闭(例如发送不应期待有效负载正文的 GET 请求时),则为 true。exclusive <boolean> 当 true 和 parent 标识父流时,创建的流将成为父流的唯一直接依赖项,所有其他现有依赖项都成为新创建流的依赖项。
默认值: false。parent <number> 指定新创建的流所依赖的流的数字标识符。weight <number> 指定流相对于具有相同 parent 的其他流的相对依赖性。
该值为 1 到 256(含)之间的数字。waitForTrailers <boolean> 当为 true 时,Http2Stream 将在发送完最后的 DATA 帧后触发 'wantTrailers' 事件。signal <AbortSi