源代码: 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