HTTP/2
[历史]
版本 | 变更 |
---|---|
v15.0.0 | 现在可以发送/接收带有 host 头部(带有或不带有 :authority )的请求。 |
v15.3.0, v14.17.0 | 可以使用 AbortSignal 中断请求。 |
v10.10.0 | HTTP/2 现在已稳定。之前,它是实验性的。 |
v8.4.0 | 在 v8.4.0 版本中添加 |
源代码: lib/http2.js
node:http2
模块提供了一个 HTTP/2 协议的实现。可以使用以下方式访问它:
const http2 = require('node:http2')
判断是否不支持加密
Node.js 可能在构建时未包含对 node:crypto
模块的支持。在这种情况下,尝试从 node:http2
导入或调用 require('node:http2')
将导致抛出错误。
使用 CommonJS 时,可以使用 try/catch 捕获抛出的错误:
let http2
try {
http2 = require('node:http2')
} catch (err) {
console.error('http2 支持已禁用!')
}
使用词法 ESM import
关键字时,只有在 在 尝试加载模块(例如,使用预加载模块)之前注册了 process.on('uncaughtException')
的处理程序时,才能捕获错误。
使用 ESM 时,如果代码有可能在未启用加密支持的 Node.js 版本上运行,请考虑使用 import()
函数而不是词法 import
关键字:
let http2
try {
http2 = await import('node:http2')
} catch (err) {
console.error('http2 支持已禁用!')
}
核心 API
核心 API 提供了一个低级接口,专门用于支持 HTTP/2 协议特性。它并非设计为与现有的 HTTP/1 模块 API 兼容。但是,兼容性 API 是兼容的。
http2
核心 API 在客户端和服务器之间比 http
API 更对称。例如,大多数事件,例如 'error'
、'connect'
和 'stream'
,可以由客户端代码或服务器端代码发出。
服务端示例
以下示例演示了使用核心 API 的简单 HTTP/2 服务器。由于没有已知的浏览器支持 未加密的 HTTP/2,因此在与浏览器客户端通信时,需要使用 http2.createSecureServer()
。
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'
const server = createSecureServer({
key: readFileSync('localhost-privkey.pem'),
cert: readFileSync('localhost-cert.pem'),
})
server.on('error', err => console.error(err))
server.on('stream', (stream, headers) => {
// stream is a Duplex
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200,
})
stream.end('<h1>Hello World</h1>')
})
server.listen(8443)
const http2 = require('node:http2')
const fs = require('node: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 is a Duplex
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 客户端的示例:
import { connect } from 'node:http2'
import { readFileSync } from 'node:fs'
const client = connect('https://localhost:8443', {
ca: 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()
const http2 = require('node:http2')
const fs = require('node: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
新增于: v8.4.0
- 继承自: <EventEmitter>
http2.Http2Session
类的实例代表 HTTP/2 客户端和服务器之间的一个活动通信会话。用户代码不应该直接构造此类的实例。
每个 Http2Session
实例的行为会略有不同,具体取决于它是作为服务器还是客户端运行。http2session.type
属性可用于确定 Http2Session
的运行模式。在服务器端,用户代码很少需要直接使用 Http2Session
对象,大多数操作通常都是通过与 Http2Server
或 Http2Stream
对象的交互来完成的。
用户代码不会直接创建 Http2Session
实例。服务器端的 Http2Session
实例是由 Http2Server
实例在接收到新的 HTTP/2 连接时创建的。客户端的 Http2Session
实例是使用 http2.connect()
方法创建的。
Http2Session
和套接字
每个 Http2Session
实例在其创建时都与一个 net.Socket
或 tls.TLSSocket
关联。当 Socket
或 Http2Session
被销毁时,两者都会被销毁。
由于 HTTP/2 协议施加的特定序列化和处理要求,不建议用户代码从绑定到 Http2Session
的 Socket
实例读取数据或向其写入数据。这样做可能会使 HTTP/2 会话进入不确定的状态,导致会话和套接字变得不可用。
一旦 Socket
已绑定到 Http2Session
,用户代码应该只依赖 Http2Session
的 API。
事件:'close'
新增于:v8.4.0
一旦 Http2Session
被销毁,就会发出 'close'
事件。其监听器不期望任何参数。
事件:'connect'
新增于:v8.4.0
session
<Http2Session>socket
<net.Socket>
一旦 Http2Session
成功连接到远程对等体并且可以开始通信,就会发出 'connect'
事件。
用户代码通常不会直接监听此事件。
事件: 'error'
新增于: v8.4.0
error
<Error>
当 Http2Session
处理过程中发生错误时,将发出 'error'
事件。
事件: 'frameError'
新增于: v8.4.0
当尝试在会话上发送帧时发生错误时,将发出 'frameError'
事件。如果无法发送的帧与特定的 Http2Stream
相关联,则会尝试在 Http2Stream
上发出 'frameError'
事件。
如果 'frameError'
事件与流相关联,则该流将在 'frameError'
事件之后立即关闭并销毁。如果该事件与流无关,则 Http2Session
将在 'frameError'
事件之后立即关闭。
事件:'goaway'
新增于:v8.4.0
errorCode
<数字>GOAWAY
帧中指定的 HTTP/2 错误代码。lastStreamID
<数字> 远程对等端成功处理的最后一个流的 ID(如果未指定 ID,则为0
)。opaqueData
<Buffer> 如果GOAWAY
帧中包含其他不透明数据,则将传递包含该数据的Buffer
实例。
当接收到 GOAWAY
帧时,将发出 'goaway'
事件。
当发出 'goaway'
事件时,Http2Session
实例将自动关闭。
事件:'localSettings'
新增于:v8.4.0
settings
<HTTP/2 设置对象> 收到的SETTINGS
帧的副本。
当收到确认的 SETTINGS
帧时,将发出 'localSettings'
事件。
使用 http2session.settings()
提交新设置时,修改后的设置只有在发出 'localSettings'
事件后才会生效。
session.settings({ enablePush: false })
session.on('localSettings', settings => {
/* 使用新设置 */
})
事件: 'ping'
新增于: v10.12.0
payload
<Buffer>PING
帧的 8 字节有效负载
'ping'
事件在接收到来自已连接对端的 PING
帧时发出。
事件: 'remoteSettings'
新增于: v8.4.0
settings
<HTTP/2 设置对象> 收到的SETTINGS
帧的副本。
'remoteSettings'
事件在接收到来自已连接对端的新的 SETTINGS
帧时发出。
session.on('remoteSettings', settings => {
/* 使用新的设置 */
})
事件: 'stream'
新增于: v8.4.0
stream
<Http2Stream> 流的引用headers
<HTTP/2 头部对象> 描述头部的对象flags
<数字> 关联的数字标志rawHeaders
<数组> 包含原始头部名称及其相应值的数组。
'stream'
事件在创建新的 Http2Stream
时发出。
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'
事件注册一个处理程序,如下例所示:
import { createServer } from 'node:http2'
// 创建一个未加密的 HTTP/2 服务器
const server = 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(8000)
const http2 = require('node: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(8000)
即使 HTTP/2 流和网络套接字并非一一对应,网络错误也会破坏每个单独的流,并且必须在流级别进行处理,如上所示。
事件:'timeout'
新增于:v8.4.0
在使用 http2session.setTimeout()
方法为该 Http2Session
设置超时时间后,如果在配置的毫秒数后 Http2Session
没有活动,则会发出 'timeout'
事件。其监听器不期望任何参数。
session.setTimeout(2000)
session.on('timeout', () => {
/* .. */
})
http2session.alpnProtocol
新增于:v9.4.0
如果 Http2Session
尚未连接到套接字,则值为 undefined
;如果 Http2Session
未连接到 TLSSocket
,则值为 h2c
;否则将返回连接的 TLSSocket
自身的 alpnProtocol
属性的值。
http2session.close([callback])
新增于:v9.4.0
callback
<函数>
优雅地关闭 Http2Session
,允许任何现有的流自行完成,并阻止创建新的 Http2Stream
实例。关闭后,如果没有任何打开的 Http2Stream
实例,则可能调用 http2session.destroy()
。
如果指定,则 callback
函数将注册为 'close'
事件的处理程序。
http2session.closed
新增于:v9.4.0
如果此 Http2Session
实例已关闭,则为 true
,否则为 false
。
http2session.connecting
新增于:v10.0.0
如果此 Http2Session
实例仍在连接中,则为 true
,在发出 connect
事件和/或调用 http2.connect
回调之前将设置为 false
。
http2session.destroy([error][, code])
新增于:v8.4.0
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
新增于:v8.4.0
如果此 Http2Session
实例已被销毁且不再可以使用,则值为 true
,否则为 false
。
http2session.encrypted
新增于:v9.4.0
如果 Http2Session
会话套接字尚未连接,则值为 undefined
;如果 Http2Session
通过 TLSSocket
连接,则值为 true
;如果 Http2Session
连接到任何其他类型的套接字或流,则值为 false
。
http2session.goaway([code[, lastStreamID[, opaqueData]]])
新增于:v9.4.0
code
<数字> 一个 HTTP/2 错误代码lastStreamID
<数字> 最后处理的Http2Stream
的数字 IDopaqueData
<Buffer> | <TypedArray> | <DataView> 一个TypedArray
或DataView
实例,包含要在GOAWAY
帧中携带的附加数据。
向已连接的对等方发送 GOAWAY
帧,不会关闭 Http2Session
。
http2session.localSettings
新增于:v8.4.0
一个无原型对象,描述了此 Http2Session
的当前本地设置。本地设置仅限于 此 Http2Session
实例。
http2session.originSet
新增于:v9.4.0
如果 Http2Session
连接到 TLSSocket
,则 originSet
属性将返回一个 Array
,其中包含 Http2Session
可能被认为是权威的来源。
originSet
属性仅在使用安全的 TLS 连接时可用。
http2session.pendingSettingsAck
新增于:v8.4.0
指示 Http2Session
是否当前正在等待已发送 SETTINGS
帧的确认。调用 http2session.settings()
方法后将为 true
。一旦所有已发送的 SETTINGS
帧都已确认,则将为 false
。
http2session.ping([payload, ]callback)
[历史]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.9.3 | 新增于:v8.9.3 |
payload
<Buffer> | <TypedArray> | <DataView> 可选 ping 负载。callback
<Function>- 返回值: <boolean>
向已连接的 HTTP/2 对等端发送 PING
帧。必须提供 callback
函数。如果发送了 PING
,则该方法将返回 true
,否则返回 false
。
未确认的 ping 的最大数量由 maxOutstandingPings
配置选项确定。默认最大值为 10。
如果提供,payload
必须是包含 8 字节数据的 Buffer
、TypedArray
或 DataView
,这些数据将与 PING
一起传输并在 ping 确认时返回。
回调将使用三个参数调用:一个错误参数,如果 PING
成功确认,则该参数为 null
;一个 duration
参数,报告自发送 ping 并收到确认以来经过的毫秒数;以及一个包含 8 字节 PING
负载的 Buffer
。
session.ping(Buffer.from('abcdefgh'), (err, duration, payload) => {
if (!err) {
console.log(`Ping 确认用时 ${duration} 毫秒`)
console.log(`负载为 '${payload.toString()}'`)
}
})
如果未指定 payload
参数,则默认负载将是标记 PING
时长开始的 64 位时间戳(小端)。
http2session.ref()
新增于: v9.4.0
调用此 Http2Session
实例底层的 net.Socket
上的 ref()
。
http2session.remoteSettings
新增于: v8.4.0
一个无原型的对象,描述此 Http2Session
的当前远程设置。远程设置由已连接的 HTTP/2 对等方设置。
http2session.setLocalWindowSize(windowSize)
新增于: v15.3.0, v14.18.0
windowSize
<数字>
设置本地端点的窗口大小。windowSize
是要设置的总窗口大小,而不是增量。
import { createServer } from 'node:http2'
const server = createServer()
const expectedWindowSize = 2 ** 20
server.on('session', session => {
// 将本地窗口大小设置为 2 ** 20
session.setLocalWindowSize(expectedWindowSize)
})
const http2 = require('node:http2')
const server = http2.createServer()
const expectedWindowSize = 2 ** 20
server.on('session', session => {
// 将本地窗口大小设置为 2 ** 20
session.setLocalWindowSize(expectedWindowSize)
})
对于 http2 客户端,正确的事件是 'connect'
或 'remoteSettings'
。
http2session.setTimeout(msecs, callback)
[历史]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于:v8.4.0 |
用于设置一个回调函数,当 msecs
毫秒后 Http2Session
没有活动时调用此函数。给定的 callback
注册为 'timeout'
事件的监听器。
http2session.socket
新增于:v8.4.0
返回一个 Proxy
对象,它充当 net.Socket
(或 tls.TLSSocket
),但将可用方法限制为可安全用于 HTTP/2 的方法。
destroy
、emit
、end
、pause
、read
、resume
和 write
将抛出代码为 ERR_HTTP2_NO_SOCKET_MANIPULATION
的错误。有关更多信息,请参见 Http2Session
和套接字。
setTimeout
方法将在此 Http2Session
上调用。
所有其他交互都将直接路由到套接字。
http2session.state
新增于: v8.4.0
提供关于 Http2Session
当前状态的各种信息。
- <对象>
effectiveLocalWindowSize
<数字>Http2Session
当前的本地(接收)流控制窗口大小。effectiveRecvDataLength
<数字> 自上次流控制WINDOW_UPDATE
以来已接收的字节数。nextStreamID
<数字> 此Http2Session
下次创建新的Http2Stream
时要使用的数字标识符。localWindowSize
<数字> 远程对等体可以在不接收WINDOW_UPDATE
的情况下发送的字节数。lastProcStreamID
<数字> 最近接收HEADERS
或DATA
帧的Http2Stream
的数字 ID。remoteWindowSize
<数字> 此Http2Session
可以在不接收WINDOW_UPDATE
的情况下发送的字节数。outboundQueueSize
<数字> 此Http2Session
出站队列中当前的帧数。deflateDynamicTableSize
<数字> 出站报头压缩状态表当前的字节大小。inflateDynamicTableSize
<数字> 入站报头压缩状态表当前的字节大小。
一个描述此 Http2Session
当前状态的对象。
http2session.settings([settings][, callback])
[历史]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | v8.4.0 版本新增 |
settings
<HTTP/2 设置对象>callback
<函数> 会话连接后或会话已连接时立即调用的回调函数。err
<错误> | <null>settings
<HTTP/2 设置对象> 更新后的settings
对象。duration
<整数>
更新此 Http2Session
的当前本地设置,并向已连接的 HTTP/2 对等端发送新的 SETTINGS
帧。
调用后,在会话等待远程对等端确认新设置期间,http2session.pendingSettingsAck
属性将为 true
。
只有在接收到 SETTINGS
确认并发出 'localSettings'
事件后,新设置才会生效。在仍然等待确认期间,可以发送多个 SETTINGS
帧。
http2session.type
新增于: v8.4.0
如果此 Http2Session
实例是服务器,则 http2session.type
将等于 http2.constants.NGHTTP2_SESSION_SERVER
;如果实例是客户端,则将等于 http2.constants.NGHTTP2_SESSION_CLIENT
。
http2session.unref()
新增于: v9.4.0
在此 Http2Session
实例的底层 net.Socket
上调用 unref()
。
类: ServerHttp2Session
新增于: v8.4.0
- 扩展自: <Http2Session>
serverhttp2session.altsvc(alt, originOrStream)
新增于: v9.4.0
alt
<字符串> 根据 RFC 7838 定义的替代服务配置的描述。originOrStream
<数字> | <字符串> | <URL> | <对象> URL 字符串,指定来源(或具有origin
属性的Object
),或者由http2stream.id
属性给出的活动Http2Stream
的数字标识符。
向已连接的客户端提交 ALTSVC
帧(如 RFC 7838 中所定义)。
import { createServer } from 'node:http2'
const server = 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)
})
const http2 = require('node: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 协议可在 TCP/IP 端口 81 上的 'example.org'
主机上使用。主机和端口必须包含在引号 ("
) 字符中。
可以指定多个备选方案,例如:'h2="example.org:81", h2=":82"'
。
协议标识符(示例中的 'h2'
)可以是任何有效的 ALPN 协议 ID。
Node.js 实现不会验证这些值的语法,而是按用户提供或从对等方接收的方式传递它们。
serverhttp2session.origin(...origins)
新增于:v10.12.0
向连接的客户端提交 ORIGIN
帧(如 RFC 8336 中所定义),以宣传服务器能够为此提供权威响应的来源集合。
import { createSecureServer } from 'node:http2'
const options = getSecureOptionsSomehow()
const server = createSecureServer(options)
server.on('stream', stream => {
stream.respond()
stream.end('ok')
})
server.on('session', session => {
session.origin('https://example.com', 'https://example.org')
})
const http2 = require('node: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
选项:
import { createSecureServer } from 'node:http2'
const options = getSecureOptionsSomehow()
options.origins = ['https://example.com', 'https://example.org']
const server = createSecureServer(options)
server.on('stream', stream => {
stream.respond()
stream.end('ok')
})
const http2 = require('node: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
新增于: v8.4.0
- 继承自: <Http2Session>
事件: 'altsvc'
新增于: v9.4.0
每当客户端接收到 ALTSVC
帧时,就会发出 'altsvc'
事件。该事件会发出 ALTSVC
值、源和流 ID。如果 ALTSVC
帧中未提供 origin
,则 origin
将为空字符串。
import { connect } from 'node:http2'
const client = connect('https://example.org')
client.on('altsvc', (alt, origin, streamId) => {
console.log(alt)
console.log(origin)
console.log(streamId)
})
const http2 = require('node:http2')
const client = http2.connect('https://example.org')
client.on('altsvc', (alt, origin, streamId) => {
console.log(alt)
console.log(origin)
console.log(streamId)
})
事件:'origin'
新增于:v10.12.0
origins
<string[]>
'origin'
事件在客户端接收到 ORIGIN
帧时发出。该事件会发出一个包含 origin
字符串数组的数组。http2session.originSet
将被更新以包含接收到的来源。
import { connect } from 'node:http2'
const client = connect('https://example.org')
client.on('origin', origins => {
for (let n = 0; n < origins.length; n++) console.log(origins[n])
})
const http2 = require('node:http2')
const client = http2.connect('https://example.org')
client.on('origin', origins => {
for (let n = 0; n < origins.length; n++) console.log(origins[n])
})
'origin'
事件仅在使用安全 TLS 连接时才会发出。
clienthttp2session.request(headers[, options])
新增于:v8.4.0
headers
<HTTP/2 Headers 对象>options
<对象>endStream
<布尔值> 如果Http2Stream
的 写入 端应该最初关闭,例如当发送一个不应期望有效负载主体的GET
请求时,则为true
。exclusive
<布尔值> 当为true
且parent
标识父流时,创建的流将成为父流的唯一直接依赖项,所有其他现有依赖项都将成为新创建流的依赖项。默认值:false
。parent
<数字> 指定新创建流所依赖的流的数字标识符。weight
<数字> 指定流相对于具有相同parent
的其他流的相对依赖性。该值是一个介于1
和256
(含)之间的数字。waitForTrailers
<布尔值> 当为true
时,在发送最后一个DATA
帧后,Http2Stream
将发出'wantTrailers'
事件。signal
<AbortSignal> 可用于中止正在进行的请求的 AbortSignal。
仅对于 HTTP/2 客户端 Http2Session
实例,http2session.request()
创建并返回一个 Http2Stream
实例,该实例可用于向已连接的服务器发送 HTTP/2 请求。
当第一次创建 ClientHttp2Session
时,套接字可能尚未连接。如果在此期间调用 clienthttp2session.request()
,则实际请求将被推迟,直到套接字准备好为止。如果在执行实际请求之前关闭了 session
,则会抛出 ERR_HTTP2_GOAWAY_SESSION
。
只有当 http2session.type
等于 http2.constants.NGHTTP2_SESSION_CLIENT
时,此方法才可用。
import { connect, constants } from 'node:http2'
const clientSession = connect('https://localhost:1234')
const { HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS } = constants
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' })
req.on('response', headers => {
console.log(headers[HTTP2_HEADER_STATUS])
req.on('data', chunk => {
/* .. */
})
req.on('end', () => {
/* .. */
})
})
const http2 = require('node:http2')
const clientSession = http2.connect('https://localhost:1234')
const { HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS } = http2.constants
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' })
req.on('response', headers => {
console.log(headers[HTTP2_HEADER_STATUS])
req.on('data', chunk => {
/* .. */
})
req.on('end', () => {
/* .. */
})
})
当设置 options.waitForTrailers
选项时,在将要发送的有效负载数据的最后一块排队后,立即发出 'wantTrailers'
事件。然后可以调用 http2stream.sendTrailers()
方法向对等方发送尾部标头。
当设置 options.waitForTrailers
时,Http2Stream
在传输最后一个 DATA
帧时不会自动关闭。用户代码必须调用 http2stream.sendTrailers()
或 http2stream.close()
来关闭 Http2Stream
。
当使用 AbortSignal
设置 options.signal
然后调用相应 AbortController
上的 abort
时,请求将发出一个带有 AbortError
错误的 'error'
事件。
:method
和 :path
伪标头未在 headers
中指定,它们分别默认为:
:method
='GET'
:path
=/
类: Http2Stream
新增于: v8.4.0
- 继承自: <stream.Duplex>
Http2Stream
类的每个实例都表示通过 Http2Session
实例进行的双向 HTTP/2 通信流。任何单个 Http2Session
在其生命周期内最多可以拥有 231-1 个 Http2Stream
实例。
用户代码不会直接构造 Http2Stream
实例。而是由 Http2Session
实例创建、管理并提供给用户代码。在服务器端,Http2Stream
实例是在响应传入的 HTTP 请求时创建的(并通过 'stream'
事件传递给用户代码),或者是在调用 http2stream.pushStream()
方法时创建的。在客户端,当调用 http2session.request()
方法时,或者响应传入的 'push'
事件时,会创建并返回 Http2Stream
实例。
Http2Stream
类是 ServerHttp2Stream
和 ClientHttp2Stream
类的基类,每个类分别由服务器端或客户端专门使用。
所有 Http2Stream
实例都是 Duplex
流。Duplex
的 Writable
端用于向连接的节点发送数据,而 Readable
端用于接收连接的节点发送的数据。
Http2Stream
的默认文本字符编码为 UTF-8。当使用 Http2Stream
发送文本时,使用 'content-type'
头设置字符编码。
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200,
})
Http2Stream
生命周期
创建
在服务器端,ServerHttp2Stream
实例在以下情况下创建:
- 收到一个新的 HTTP/2
HEADERS
帧,且该帧的流 ID 未被使用; - 调用
http2stream.pushStream()
方法。
在客户端,ClientHttp2Stream
实例在调用 http2session.request()
方法时创建。
在客户端,如果父 Http2Session
尚未完全建立,则 http2session.request()
返回的 Http2Stream
实例可能无法立即使用。在这种情况下,对 Http2Stream
的调用操作将被缓冲,直到发出 'ready'
事件。用户代码很少需要直接处理 'ready'
事件。可以通过检查 http2stream.id
的值来确定 Http2Stream
的就绪状态。如果该值为 undefined
,则该流尚未准备好使用。
销毁
所有 Http2Stream
实例在以下情况下销毁:
- 连接的端点收到该流的
RST_STREAM
帧,并且(仅限客户端流)已读取挂起的數據。 - 调用
http2stream.close()
方法,并且(仅限客户端流)已读取挂起的數據。 - 调用
http2stream.destroy()
或http2session.destroy()
方法。
当 Http2Stream
实例被销毁时,将尝试向连接的端点发送 RST_STREAM
帧。
当 Http2Stream
实例被销毁时,将发出 'close'
事件。因为 Http2Stream
是 stream.Duplex
的实例,如果流数据当前正在流动,则还会发出 'end'
事件。如果使用传递的 Error
作为第一个参数调用 http2stream.destroy()
,则也可能会发出 'error'
事件。
Http2Stream
销毁后,http2stream.destroyed
属性将为 true
,而 http2stream.rstCode
属性将指定 RST_STREAM
错误代码。销毁后,Http2Stream
实例将不再可用。
事件: 'aborted'
新增于: v8.4.0
当 Http2Stream
实例在通信中途异常中止时,会发出 'aborted'
事件。其监听器不接收任何参数。
只有当 Http2Stream
的可写端未结束时,才会发出 'aborted'
事件。
事件: 'close'
新增于: v8.4.0
当 Http2Stream
被销毁时,会发出 'close'
事件。一旦发出此事件,Http2Stream
实例将不再可用。
关闭流时使用的 HTTP/2 错误代码可以使用 http2stream.rstCode
属性检索。如果代码不是 NGHTTP2_NO_ERROR
(0
),则也会发出 'error'
事件。
事件: 'error'
新增于: v8.4.0
error
<Error>
当处理 Http2Stream
期间发生错误时,会发出 'error'
事件。
事件: 'frameError'
新增于: v8.4.0
当尝试发送帧时发生错误时,会发出 'frameError'
事件。调用时,处理程序函数将接收一个整数参数,用于标识帧类型,以及一个整数参数,用于标识错误代码。'frameError'
事件发出后,Http2Stream
实例将立即被销毁。
事件:'ready'
新增于:v8.4.0
当 Http2Stream
已打开,已分配 id
并且可以使用时,将发出 'ready'
事件。监听器不期望任何参数。
事件:'timeout'
新增于:v8.4.0
在使用 http2stream.setTimeout()
设置的毫秒数内未收到此 Http2Stream
的任何活动后,将发出 'timeout'
事件。其监听器不期望任何参数。
事件:'trailers'
新增于:v8.4.0
headers
<HTTP/2 Headers 对象> 描述报头的对象flags
<数字> 关联的数字标志
当接收到与尾部报头字段关联的报头块时,将发出 'trailers'
事件。监听器回调函数将传入与报头关联的 HTTP/2 Headers 对象 和标志。
如果在接收到尾部报头之前调用了 http2stream.end()
并且未读取或监听传入的数据,则可能不会发出此事件。
stream.on('trailers', (headers, flags) => {
console.log(headers)
})
事件: 'wantTrailers'
新增于: v10.0.0
当 Http2Stream
已将最终的 DATA
帧排队发送到帧上,并且 Http2Stream
已准备好发送尾部报头时,将发出 'wantTrailers'
事件。发起请求或响应时,必须设置 waitForTrailers
选项才能发出此事件。
http2stream.aborted
新增于: v8.4.0
如果 Http2Stream
实例异常中止,则设置为 true
。设置后,将发出 'aborted'
事件。
http2stream.bufferSize
新增于: v11.2.0, v10.16.0
此属性显示当前缓冲写入的字符数。详情请参见 net.Socket.bufferSize
。
http2stream.close(code[, callback])
[历史记录]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于: v8.4.0 |
code
<数字> 无符号 32 位整数,标识错误代码。默认值:http2.constants.NGHTTP2_NO_ERROR
(0x00
)。callback
<函数> 一个可选函数,注册用于监听'close'
事件。
通过向已连接的 HTTP/2 对等体发送 RST_STREAM
帧来关闭 Http2Stream
实例。
http2stream.closed
新增于: v9.4.0
如果 Http2Stream
实例已关闭,则设置为 true
。
http2stream.destroyed
新增于: v8.4.0
如果 Http2Stream
实例已被销毁且不再可用,则设置为 true
。
http2stream.endAfterHeaders
新增于: v10.11.0
如果在接收到的请求或响应 HEADERS 帧中设置了 END_STREAM
标志,则设置为 true
,这表示不应接收任何其他数据,并且 Http2Stream
的可读端将被关闭。
http2stream.id
新增于: v8.4.0
此 Http2Stream
实例的数字流标识符。如果尚未分配流标识符,则设置为 undefined
。
http2stream.pending
新增于: v9.4.0
如果 Http2Stream
实例尚未分配数字流标识符,则设置为 true
。
http2stream.priority(options)
新增于: v8.4.0
options
<对象>
更新此 Http2Stream
实例的优先级。
http2stream.rstCode
新增于: v8.4.0
当 Http2Stream
在收到连接对等方的 RST_STREAM
帧、调用 http2stream.close()
或 http2stream.destroy()
后被销毁时,设置为报告的 RST_STREAM
错误代码。如果 Http2Stream
未关闭,则为 undefined
。
http2stream.sentHeaders
新增于: v9.5.0
一个包含为此 Http2Stream
发送的出站头的对象。
http2stream.sentInfoHeaders
新增于: v9.5.0
一个包含为此 Http2Stream
发送的出站信息(附加)头的对象的数组。
http2stream.sentTrailers
新增于: v9.5.0
一个包含为此 HttpStream
发送的出站尾部的对象。
http2stream.session
新增于:v8.4.0
指向拥有此 Http2Stream
实例的 Http2Session
实例的引用。Http2Stream
实例销毁后,该值将为 undefined
。
http2stream.setTimeout(msecs, callback)
[历史记录]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于:v8.4.0 |
msecs
<number>callback
<Function>
import { connect, constants } from 'node:http2'
const client = connect('http://example.org:8000')
const { NGHTTP2_CANCEL } = constants
const req = client.request({ ':path': '/' })
// 如果 5 秒后没有活动,则取消流
req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL))
const http2 = require('node:http2')
const client = http2.connect('http://example.org:8000')
const { NGHTTP2_CANCEL } = http2.constants
const req = client.request({ ':path': '/' })
// 如果 5 秒后没有活动,则取消流
req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL))
http2stream.state
新增于: v8.4.0
提供关于Http2Stream
当前状态的各种信息。
- <对象>
localWindowSize
<数字> 连接的端点可以在不接收WINDOW_UPDATE
的情况下为此Http2Stream
发送的字节数。state
<数字> 由nghttp2
确定的Http2Stream
底层当前状态的标志。localClose
<数字> 如果此Http2Stream
已在本地关闭,则为1
。remoteClose
<数字> 如果此Http2Stream
已在远程关闭,则为1
。sumDependencyWeight
<数字> 使用PRIORITY
帧指定的所有依赖于此Http2Stream
的Http2Stream
实例的总权重。weight
<数字> 此Http2Stream
的优先级权重。
此Http2Stream
的当前状态。
http2stream.sendTrailers(headers)
Added in: v10.0.0
headers
<HTTP/2 Headers 对象>
向已连接的 HTTP/2 对等端发送尾部 HEADERS
帧。此方法将导致 Http2Stream
立即关闭,并且必须仅在发出 'wantTrailers'
事件后才能调用。发送请求或响应时,必须设置 options.waitForTrailers
选项,以便在最后一个 DATA
帧后保持 Http2Stream
打开,以便可以发送尾部信息。
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
stream.respond(undefined, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ xyz: 'abc' })
})
stream.end('Hello World')
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
stream.respond(undefined, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ xyz: 'abc' })
})
stream.end('Hello World')
})
HTTP/1 规范禁止尾部信息包含 HTTP/2 伪标头字段(例如 ':method'
、':path'
等)。
类: ClientHttp2Stream
新增于: v8.4.0
- 继承自 <Http2Stream>
ClientHttp2Stream
类是 Http2Stream
的扩展,仅用于 HTTP/2 客户端。客户端上的 Http2Stream
实例提供诸如 'response'
和 'push'
之类的事件,这些事件仅与客户端相关。
事件: 'continue'
新增于: v8.5.0
当服务器发送 100 Continue
状态时发出,通常是因为请求包含 Expect: 100-continue
。这是一个指示客户端应发送请求正文的指令。
事件: 'headers'
新增于: v8.4.0
headers
<HTTP/2 头部对象>flags
<数字>
当为流接收到额外的头部块时,例如接收到 1xx
信息头部块时,就会发出 'headers'
事件。监听器回调函数会传递与头部关联的 HTTP/2 头部对象 和标志。
stream.on('headers', (headers, flags) => {
console.log(headers)
})
事件:'push'
新增于:v8.4.0
headers
<HTTP/2 Headers 对象>flags
<数字>
当接收到服务器推送流的响应头时,将发出 'push'
事件。监听器回调函数将传入与报头关联的 HTTP/2 Headers 对象 和标志。
stream.on('push', (headers, flags) => {
console.log(headers)
})
事件:'response'
新增于:v8.4.0
headers
<HTTP/2 Headers 对象>flags
<数字>
当从已连接的 HTTP/2 服务器接收到此流的响应 HEADERS
帧时,将发出 'response'
事件。监听器将使用两个参数调用:一个包含接收到的 HTTP/2 Headers 对象 的 Object
,以及与报头关联的标志。
import { connect } from 'node:http2'
const client = connect('https://localhost')
const req = client.request({ ':path': '/' })
req.on('response', (headers, flags) => {
console.log(headers[':status'])
})
const http2 = require('node:http2')
const client = http2.connect('https://localhost')
const req = client.request({ ':path': '/' })
req.on('response', (headers, flags) => {
console.log(headers[':status'])
})
类: ServerHttp2Stream
新增于: v8.4.0
- 继承自: <Http2Stream>
ServerHttp2Stream
类是 Http2Stream
的扩展,仅用于 HTTP/2 服务器。服务器上的 Http2Stream
实例提供了其他方法,例如 http2stream.pushStream()
和 http2stream.respond()
,这些方法仅在服务器端相关。
http2stream.additionalHeaders(headers)
新增于: v8.4.0
headers
<HTTP/2 头部对象>
向已连接的 HTTP/2 对等体发送额外的信息 HEADERS
帧。
http2stream.headersSent
新增于: v8.4.0
如果已发送头部,则为真;否则为假(只读)。
http2stream.pushAllowed
新增于: v8.4.0
映射到远程客户端最新 SETTINGS
帧的 SETTINGS_ENABLE_PUSH
标志的只读属性。如果远程对等体接受推送流,则为 true
;否则为 false
。对于同一 Http2Session
中的每个 Http2Stream
,设置都是相同的。
http2stream.pushStream(headers[, options], callback)
[历史]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于:v8.4.0 |
headers
<HTTP/2 头部对象>options
<对象>callback
<函数> 推送流启动后调用的回调函数。err
<错误>pushStream
<ServerHttp2Stream> 返回的pushStream
对象。headers
<HTTP/2 头部对象>pushStream
使用的头部对象。
启动推送流。回调函数将使用为推送流创建的新的 Http2Stream
实例作为第二个参数调用,或者将 Error
作为第一个参数调用。
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 })
stream.pushStream({ ':path': '/' }, (err, pushStream, headers) => {
if (err) throw err
pushStream.respond({ ':status': 200 })
pushStream.end('some pushed data')
})
stream.end('some data')
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 })
stream.pushStream({ ':path': '/' }, (err, pushStream, headers) => {
if (err) throw err
pushStream.respond({ ':status': 200 })
pushStream.end('some pushed data')
})
stream.end('some data')
})
不允许在 HEADERS
帧中设置推送流的权重。将 weight
值传递给 http2stream.priority
并将 silent
选项设置为 true
以启用并发流之间的服务器端带宽平衡。
不允许在推送流内调用 http2stream.pushStream()
,否则将抛出错误。
http2stream.respond([headers[, options]])
[历史]
版本 | 变更 |
---|---|
v14.5.0, v12.19.0 | 允许显式设置日期头。 |
v8.4.0 | 新增于:v8.4.0 |
headers
<HTTP/2 头部对象>options
<对象>
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 })
stream.end('some data')
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 })
stream.end('some data')
})
启动响应。当设置 options.waitForTrailers
选项时,在排队发送最后一个有效负载数据块后,将立即发出 'wantTrailers'
事件。然后可以使用 http2stream.sendTrailers()
方法向对端发送尾部标头字段。
当设置 options.waitForTrailers
时,Http2Stream
在传输最后一个 DATA
帧时不会自动关闭。用户代码必须调用 http2stream.sendTrailers()
或 http2stream.close()
来关闭 Http2Stream
。
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 }, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
stream.end('some data')
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
stream.respond({ ':status': 200 }, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
stream.end('some data')
})
http2stream.respondWithFD(fd[, headers[, options]])
[历史]
版本 | 变更 |
---|---|
v14.5.0, v12.19.0 | 允许显式设置日期头。 |
v12.12.0 | fd 选项现在可以是 FileHandle 。 |
v10.0.0 | 现在支持任何可读的文件描述符,不一定是普通文件。 |
v8.4.0 | v8.4.0 中添加 |
fd
<数字> | <FileHandle> 可读的文件描述符。headers
<HTTP/2 头部对象>options
<对象>
启动一个响应,其数据从给定的文件描述符读取。不会对给定的文件描述符进行验证。如果尝试使用文件描述符读取数据时发生错误,则 Http2Stream
将使用标准 INTERNAL_ERROR
代码使用 RST_STREAM
帧关闭。
使用时,Http2Stream
对象的 Duplex
接口将自动关闭。
import { createServer } from 'node:http2'
import { openSync, fstatSync, closeSync } from 'node:fs'
const server = createServer()
server.on('stream', stream => {
const fd = openSync('/some/file', 'r')
const stat = fstatSync(fd)
const headers = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': 'text/plain; charset=utf-8',
}
stream.respondWithFD(fd, headers)
stream.on('close', () => closeSync(fd))
})
const http2 = require('node:http2')
const fs = require('node:fs')
const server = http2.createServer()
server.on('stream', stream => {
const fd = fs.openSync('/some/file', 'r')
const stat = fs.fstatSync(fd)
const headers = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': 'text/plain; charset=utf-8',
}
stream.respondWithFD(fd, headers)
stream.on('close', () => fs.closeSync(fd))
})
可以指定可选的 options.statCheck
函数,以便用户代码有机会根据给定 fd 的 fs.Stat
详细信息设置附加内容标头。如果提供了 statCheck
函数,则 http2stream.respondWithFD()
方法将执行 fs.fstat()
调用以收集有关提供的文件描述符的详细信息。
可以使用 offset
和 length
选项将响应限制为特定范围子集。例如,这可以用于支持 HTTP Range 请求。
流关闭时不会关闭文件描述符或 FileHandle
,因此需要在不再需要时手动关闭它。不支持同时对多个流并发使用相同的文件描述符,这可能会导致数据丢失。流结束后支持重用文件描述符。
当设置 options.waitForTrailers
选项时,在排队要发送的最后一个有效负载数据块后,将立即发出 'wantTrailers'
事件。然后可以使用 http2stream.sendTrailers()
方法向对等方发送尾部标头字段。
当设置 options.waitForTrailers
时,Http2Stream
在传输最后一个 DATA
帧时不会自动关闭。用户代码必须调用 http2stream.sendTrailers()
或 http2stream.close()
来关闭 Http2Stream
。
import { createServer } from 'node:http2'
import { openSync, fstatSync, closeSync } from 'node:fs'
const server = createServer()
server.on('stream', stream => {
const fd = openSync('/some/file', 'r')
const stat = fstatSync(fd)
const headers = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': 'text/plain; charset=utf-8',
}
stream.respondWithFD(fd, headers, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
stream.on('close', () => closeSync(fd))
})
const http2 = require('node:http2')
const fs = require('node:fs')
const server = http2.createServer()
server.on('stream', stream => {
const fd = fs.openSync('/some/file', 'r')
const stat = fs.fstatSync(fd)
const headers = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': 'text/plain; charset=utf-8',
}
stream.respondWithFD(fd, headers, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
stream.on('close', () => fs.closeSync(fd))
})
http2stream.respondWithFile(path[, headers[, options]])
[历史]
版本 | 变更 |
---|---|
v14.5.0, v12.19.0 | 允许显式设置日期头。 |
v10.0.0 | 现在支持任何可读文件,不一定是常规文件。 |
v8.4.0 | 新增于:v8.4.0 |
path
<字符串> | <Buffer> | <URL>headers
<HTTP/2 头部对象>options
<对象>
发送常规文件作为响应。path
必须指定一个常规文件,否则 Http2Stream
对象将发出 'error'
事件。
使用此方法时,Http2Stream
对象的 Duplex
接口将自动关闭。
可以指定可选的 options.statCheck
函数,以便用户代码根据给定文件的 fs.Stat
详细信息设置其他内容头:
如果尝试读取文件数据时发生错误,则 Http2Stream
将使用标准 INTERNAL_ERROR
代码使用 RST_STREAM
帧关闭。如果定义了 onError
回调,则将调用它。否则流将被销毁。
使用文件路径的示例:
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
function statCheck(stat, headers) {
headers['last-modified'] = stat.mtime.toUTCString()
}
function onError(err) {
// stream.respond() 如果流已被另一端销毁,则可能会抛出异常。
try {
if (err.code === 'ENOENT') {
stream.respond({ ':status': 404 })
} else {
stream.respond({ ':status': 500 })
}
} catch (err) {
// 执行实际的错误处理。
console.error(err)
}
stream.end()
}
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { statCheck, onError })
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
function statCheck(stat, headers) {
headers['last-modified'] = stat.mtime.toUTCString()
}
function onError(err) {
// stream.respond() 如果流已被另一端销毁,则可能会抛出异常。
try {
if (err.code === 'ENOENT') {
stream.respond({ ':status': 404 })
} else {
stream.respond({ ':status': 500 })
}
} catch (err) {
// 执行实际的错误处理。
console.error(err)
}
stream.end()
}
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { statCheck, onError })
})
options.statCheck
函数也可用于通过返回 false
来取消发送操作。例如,条件请求可以检查状态结果以确定文件是否已修改,从而返回适当的 304
响应:
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
function statCheck(stat, headers) {
// 在此处检查状态...
stream.respond({ ':status': 304 })
return false // 取消发送操作
}
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { statCheck })
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
function statCheck(stat, headers) {
// 在此处检查状态...
stream.respond({ ':status': 304 })
return false // 取消发送操作
}
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { statCheck })
})
content-length
头字段将自动设置。
可以使用 offset
和 length
选项将响应限制为特定范围的子集。例如,这可以用于支持 HTTP Range 请求。
options.onError
函数也可用于处理在文件传输开始之前可能发生的任何错误。默认行为是销毁流。
设置 options.waitForTrailers
选项后,将在排队要发送的最后一个有效负载数据块后立即发出 'wantTrailers'
事件。然后可以使用 http2stream.sendTrailers()
方法向对等端发送尾部标头字段。
当设置 options.waitForTrailers
时,Http2Stream
在传输最后一个 DATA
帧时不会自动关闭。用户代码必须调用 http2stream.sendTrailers()
或 http2stream.close()
来关闭 Http2Stream
。
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', stream => {
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', stream => {
stream.respondWithFile('/some/file', { 'content-type': 'text/plain; charset=utf-8' }, { waitForTrailers: true })
stream.on('wantTrailers', () => {
stream.sendTrailers({ ABC: 'some value to send' })
})
})
类: Http2Server
新增于: v8.4.0
- 继承自: <net.Server>
Http2Server
的实例使用 http2.createServer()
函数创建。Http2Server
类不会被 node:http2
模块直接导出。
事件: 'checkContinue'
新增于: v8.5.0
request
<http2.Http2ServerRequest>response
<http2.Http2ServerResponse>
如果注册了 'request'
监听器或向 http2.createServer()
提供了回调函数,则每次收到带有 HTTP Expect: 100-continue
的请求时,都会发出 'checkContinue'
事件。如果没有监听此事件,服务器将根据需要自动响应状态码 100 Continue
。
处理此事件需要调用 response.writeContinue()
(如果客户端应该继续发送请求正文)或生成适当的 HTTP 响应(例如 400 Bad Request)(如果客户端不应该继续发送请求正文)。
当发出并处理此事件时,将不会发出 'request'
事件。
事件:'connection'
新增于:v8.4.0
socket
<stream.Duplex>
当建立新的 TCP 流时会发出此事件。socket
通常是 net.Socket
类型对象。通常用户不需要访问此事件。
此事件也可以由用户显式发出,以将连接注入 HTTP 服务器。在这种情况下,可以传递任何 Duplex
流。
事件:'request'
新增于:v8.4.0
request
<http2.Http2ServerRequest>response
<http2.Http2ServerResponse>
每次有请求时都会发出此事件。每个会话可能有多个请求。请参阅 兼容性 API。
事件:'session'
新增于:v8.4.0
session
<ServerHttp2Session>
当 Http2Server
创建新的 Http2Session
时会发出 'session'
事件。
事件: 'sessionError'
新增于: v8.4.0
error
<Error>session
<ServerHttp2Session>
当与 Http2Server
关联的 Http2Session
对象发出 'error'
事件时,会发出 'sessionError'
事件。
事件: 'stream'
新增于: v8.4.0
stream
<Http2Stream> 指向流的引用headers
<HTTP/2 Headers 对象> 描述报头的对象flags
<数字> 关联的数字标志rawHeaders
<数组> 包含原始报头名称及其相应值的数组。
当与服务器关联的 Http2Session
发出 'stream'
事件时,会发出 'stream'
事件。
另见 Http2Session
的 'stream'
事件。
import { createServer, constants } from 'node:http2'
const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE } = constants
const server = createServer()
server.on('stream', (stream, headers, flags) => {
const method = headers[HTTP2_HEADER_METHOD]
const path = headers[HTTP2_HEADER_PATH]
// ...
stream.respond({
[HTTP2_HEADER_STATUS]: 200,
[HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
})
stream.write('hello ')
stream.end('world')
})
const http2 = require('node:http2')
const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE } = http2.constants
const server = http2.createServer()
server.on('stream', (stream, headers, flags) => {
const method = headers[HTTP2_HEADER_METHOD]
const path = headers[HTTP2_HEADER_PATH]
// ...
stream.respond({
[HTTP2_HEADER_STATUS]: 200,
[HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
})
stream.write('hello ')
stream.end('world')
})
事件:'timeout'
[历史]
版本 | 变更 |
---|---|
v13.0.0 | 默认超时时间从 120 秒更改为 0(无超时)。 |
v8.4.0 | 新增于:v8.4.0 |
当服务器在使用 http2server.setTimeout()
设置的毫秒数内没有活动时,将发出 'timeout'
事件。默认值: 0(无超时)
server.close([callback])
新增于:v8.4.0
callback
<函数>
停止服务器建立新的会话。由于 HTTP/2 会话的持久性,这不会阻止创建新的请求流。要优雅地关闭服务器,请对所有活动会话调用 http2session.close()
。
如果提供了 callback
,则只有在所有活动会话都关闭后才会调用它,尽管服务器已经停止允许新的会话。有关更多详细信息,请参阅 net.Server.close()
。
server[Symbol.asyncDispose]()
新增于:v20.4.0
调用 server.close()
并返回一个 promise,该 promise 在服务器关闭时完成。
server.setTimeout([msecs][, callback])
[历史记录]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v13.0.0 | 默认超时时间从 120 秒更改为 0(无超时)。 |
v8.4.0 | 新增于:v8.4.0 |
msecs
<number> 默认值: 0(无超时)callback
<Function>- 返回值: <Http2Server>
用于设置 http2 服务器请求的超时值,并在 msecs
毫秒后 Http2Server
没有活动时调用回调函数。
给定的回调函数被注册为 'timeout'
事件的监听器。
如果 callback
不是函数,则会抛出一个新的 ERR_INVALID_ARG_TYPE
错误。
server.timeout
[历史]
版本 | 变更 |
---|---|
v13.0.0 | 默认超时时间从 120 秒更改为 0(无超时)。 |
v8.4.0 | 新增于:v8.4.0 |
- <数字> 超时时间(毫秒)。默认值: 0(无超时)
套接字在被认为超时之前的不活动毫秒数。
值为 0
将禁用传入连接的超时行为。
套接字超时逻辑在连接时设置,因此更改此值仅影响与服务器的新连接,而不影响任何现有连接。
server.updateSettings([settings])
新增于:v15.1.0, v14.17.0
settings
<HTTP/2 设置对象>
用于使用提供的设置更新服务器。
对于无效的 settings
值,将抛出 ERR_HTTP2_INVALID_SETTING_VALUE
错误。
对于无效的 settings
参数,将抛出 ERR_INVALID_ARG_TYPE
错误。
类:Http2SecureServer
新增于:v8.4.0
- 继承自:<tls.Server>
Http2SecureServer
的实例是使用 http2.createSecureServer()
函数创建的。Http2SecureServer
类不是由 node:http2
模块直接导出的。
事件:'checkContinue'
新增于:v8.5.0
request
<http2.Http2ServerRequest>response
<http2.Http2ServerResponse>
如果注册了 'request'
监听器,或者为 http2.createSecureServer()
提供了回调函数,则每次收到带有 HTTP Expect: 100-continue
的请求时,都会发出 'checkContinue'
事件。如果没有监听此事件,服务器将根据需要自动响应状态码 100 Continue
。
处理此事件涉及到:如果客户端应该继续发送请求体,则调用 response.writeContinue()
;如果客户端不应该继续发送请求体,则生成相应的 HTTP 响应(例如 400 Bad Request)。
当此事件被发出并处理后,'request'
事件将不会被发出。
事件:'connection'
新增于:v8.4.0
socket
<stream.Duplex>
当新的 TCP 流建立时,在 TLS 握手开始之前,会发出此事件。socket
通常是 net.Socket
类型的对象。通常用户不需要访问此事件。
此事件也可以由用户显式发出,以将连接注入 HTTP 服务器。在这种情况下,可以传递任何 Duplex
流。
事件:'request'
新增于:v8.4.0
request
<http2.Http2ServerRequest>response
<http2.Http2ServerResponse>
每次有请求时都会发出此事件。每个会话可能有多个请求。请参阅 兼容性 API。
事件:'session'
新增于:v8.4.0
session
<ServerHttp2Session>
当 Http2SecureServer
创建新的 Http2Session
时,会发出 'session'
事件。
事件: 'sessionError'
新增于: v8.4.0
error
<Error>session
<ServerHttp2Session>
当与 Http2SecureServer
关联的 Http2Session
对象发出 'error'
事件时,将发出 'sessionError'
事件。
事件: 'stream'
新增于: v8.4.0
stream
<Http2Stream> 流的引用headers
<HTTP/2 Headers 对象> 描述报头的对象flags
<数字> 关联的数字标志rawHeaders
<数组> 包含原始报头名称及其相应值的数组。
当与服务器关联的 Http2Session
发出 'stream'
事件时,将发出 'stream'
事件。
另见 Http2Session
的 'stream'
事件。
import { createSecureServer, constants } from 'node:http2'
const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE } = constants
const options = getOptionsSomehow()
const server = createSecureServer(options)
server.on('stream', (stream, headers, flags) => {
const method = headers[HTTP2_HEADER_METHOD]
const path = headers[HTTP2_HEADER_PATH]
// ...
stream.respond({
[HTTP2_HEADER_STATUS]: 200,
[HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
})
stream.write('hello ')
stream.end('world')
})
const http2 = require('node:http2')
const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE } = http2.constants
const options = getOptionsSomehow()
const server = http2.createSecureServer(options)
server.on('stream', (stream, headers, flags) => {
const method = headers[HTTP2_HEADER_METHOD]
const path = headers[HTTP2_HEADER_PATH]
// ...
stream.respond({
[HTTP2_HEADER_STATUS]: 200,
[HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
})
stream.write('hello ')
stream.end('world')
})
事件:'timeout'
新增于:v8.4.0
当服务器在使用 http2secureServer.setTimeout()
设置的毫秒数内没有活动时,将发出 'timeout'
事件。默认值: 2 分钟。
事件:'unknownProtocol'
[历史记录]
版本 | 变更 |
---|---|
v19.0.0 | 此事件仅在客户端在 TLS 握手期间未传输 ALPN 扩展时才发出。 |
v8.4.0 | 新增于:v8.4.0 |
socket
<stream.Duplex>
当连接的客户端未能协商允许的协议(即 HTTP/2 或 HTTP/1.1)时,将发出 'unknownProtocol'
事件。事件处理程序接收用于处理的套接字。如果未为此事件注册任何侦听器,则连接将终止。可以使用传递给 http2.createSecureServer()
的 'unknownProtocolTimeout'
选项指定超时。
在早期版本的 Node.js 中,如果 allowHTTP1
为 false
,并且在 TLS 握手期间,客户端要么不发送 ALPN 扩展,要么发送的 ALPN 扩展不包含 HTTP/2 (h2
),则会发出此事件。较新版本的 Node.js 仅在 allowHTTP1
为 false
且客户端未发送 ALPN 扩展时才发出此事件。如果客户端发送的 ALPN 扩展不包含 HTTP/2(或者如果 allowHTTP1
为 true
,则不包含 HTTP/1.1),则 TLS 握手将失败,并且不会建立安全连接。
请参见 兼容性 API。
server.close([callback])
新增于: v8.4.0
callback
<Function>
停止服务器建立新的会话。由于 HTTP/2 会话的持久性,这不会阻止创建新的请求流。要优雅地关闭服务器,请对所有活动会话调用 http2session.close()
。
如果提供了 callback
,则只有在所有活动会话都关闭后才会调用它,尽管服务器已经停止允许新的会话。有关更多详细信息,请参阅 tls.Server.close()
。
server.setTimeout([msecs][, callback])
[历史记录]
版本 | 变更 |
---|---|
v18.0.0 | 将无效的回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于: v8.4.0 |
msecs
<number> 默认值:120000
(2 分钟)callback
<Function>- 返回值: <Http2SecureServer>
用于设置 http2 安全服务器请求的超时值,并设置一个回调函数,该函数在 msecs
毫秒后 Http2SecureServer
上没有活动时被调用。
给定的回调函数注册为 'timeout'
事件的监听器。
如果 callback
不是函数,则会抛出一个新的 ERR_INVALID_ARG_TYPE
错误。
server.timeout
[历史]
版本 | 变更 |
---|---|
v13.0.0 | 默认超时时间从 120s 更改为 0(无超时)。 |
v8.4.0 | 在 v8.4.0 中添加 |
- <数字> 超时时间(毫秒)。默认值: 0(无超时)
套接字在被认为超时之前的不活动毫秒数。
值为 0
将禁用传入连接的超时行为。
套接字超时逻辑在连接时设置,因此更改此值仅会影响服务器的新连接,而不会影响任何现有连接。
server.updateSettings([settings])
在 v15.1.0、v14.17.0 中添加
settings
<HTTP/2 设置对象>
用于使用提供的设置更新服务器。
对于无效的 settings
值,将抛出 ERR_HTTP2_INVALID_SETTING_VALUE
。
对于无效的 settings
参数,将抛出 ERR_INVALID_ARG_TYPE
。
http2.createServer([options][, onRequestHandler])
[历史]
版本 | 变更 |
---|---|
v23.0.0 | 添加了 streamResetBurst 和 streamResetRate 。 |
v13.0.0 | PADDING_STRATEGY_CALLBACK 已等效于提供 PADDING_STRATEGY_ALIGNED ,并且 selectPadding 已被移除。 |
v13.3.0, v12.16.0 | 添加了 maxSessionRejectedStreams 选项,默认值为 100。 |
v13.3.0, v12.16.0 | 添加了 maxSessionInvalidFrames 选项,默认值为 1000。 |
v12.4.0 | options 参数现在支持 net.createServer() 选项。 |
v15.10.0, v14.16.0, v12.21.0, v10.24.0 | 添加了 unknownProtocolTimeout 选项,默认值为 10000。 |
v14.4.0, v12.18.0, v10.21.0 | 添加了 maxSettings 选项,默认值为 32。 |
v9.6.0 | 添加了 Http1IncomingMessage 和 Http1ServerResponse 选项。 |
v8.9.3 | 添加了 maxOutstandingPings 选项,默认限制为 10。 |
v8.9.3 | 添加了 maxHeaderListPairs 选项,默认限制为 128 个报头对。 |
v8.4.0 | 在 v8.4.0 中添加 |
options
<对象>maxDeflateDynamicTableSize
<数字> 设置用于压缩报头字段的最大动态表大小。默认值:4Kib
。maxSettings
<数字> 设置每个SETTINGS
帧的最大设置条目数。允许的最小值为1
。默认值:32
。maxSessionMemory
<数字> 设置Http2Session
允许使用的最大内存。该值以兆字节表示,例如1
等于 1 兆字节。允许的最小值为1
。这是一个基于信用的限制,现有的Http2Stream
可能会导致超过此限制,但在超过此限制时,将拒绝新的Http2Stream
实例。当前的Http2Stream
会话数量、报头压缩表当前的内存使用情况、当前排队要发送的数据以及未确认的PING
和SETTINGS
帧都计入当前限制。默认值:10
。maxHeaderListPairs
<数字> 设置报头条目的最大数量。这类似于node:http
模块中的server.maxHeadersCount
或request.maxHeadersCount
。最小值为4
。默认值:128
。maxOutstandingPings
<数字> 设置未确认的未完成 ping 的最大数量。默认值:10
。maxSendHeaderBlockLength
<数字> 设置序列化压缩报头块的最大允许大小。尝试发送超过此限制的报头将导致发出'frameError'
事件,并关闭和销毁流。虽然这将整个报头块的最大允许大小设置为,但nghttp2
(内部 http2 库)对每个解压缩的键/值对都有65536
的限制。paddingStrategy
<数字> 用于确定为HEADERS
和DATA
帧使用多少填充的策略。默认值:http2.constants.PADDING_STRATEGY_NONE
。值可以是以下之一:http2.constants.PADDING_STRATEGY_NONE
: 不应用填充。http2.constants.PADDING_STRATEGY_MAX
: 应用内部实现确定的最大填充量。http2.constants.PADDING_STRATEGY_ALIGNED
: 尝试应用足够的填充以确保总帧长度(包括 9 字节的报头)是 8 的倍数。对于每个帧,都有一个最大允许的填充字节数,该字节数由当前流量控制状态和设置确定。如果此最大值小于确保对齐所需的计算量,则使用最大值,并且总帧长度不一定是 8 字节的对齐。peerMaxConcurrentStreams
<数字> 设置远程对等方的最大并发流数,就像已接收SETTINGS
帧一样。如果远程对等方设置了自己的maxConcurrentStreams
值,则将被覆盖。默认值:100
。maxSessionInvalidFrames
<整数> 设置在会话关闭之前将容忍的最大无效帧数。默认值:1000
。maxSessionRejectedStreams
<整数> 设置在会话关闭之前将容忍的最大被拒绝的创建流数。每个拒绝都与NGHTTP2_ENHANCE_YOUR_CALM
错误相关联,该错误应告诉对等方不要再打开任何流,因此继续打开流被认为是行为不端对等方的标志。默认值:100
。settings
<HTTP/2 设置对象> 连接时发送到远程对等方的初始设置。streamResetBurst
<数字> 和streamResetRate
<数字> 设置传入流重置(RST_STREAM 帧)的速率限制。两个设置都必须设置才能生效,默认值分别为 1000 和 33。remoteCustomSettings
<数组> 整数值数组确定设置类型,这些类型包含在接收到的 remoteSettings 的CustomSettings
属性中。有关允许的设置类型的更多信息,请参阅Http2Settings
对象的CustomSettings
属性。Http1IncomingMessage
<http.IncomingMessage> 指定用于 HTTP/1 回退的IncomingMessage
类。对于扩展原始http.IncomingMessage
很有用。默认值:http.IncomingMessage
。Http1ServerResponse
<http.ServerResponse> 指定用于 HTTP/1 回退的ServerResponse
类。对于扩展原始http.ServerResponse
很有用。默认值:http.ServerResponse
。Http2ServerRequest
<http2.Http2ServerRequest> 指定要使用的Http2ServerRequest
类。对于扩展原始Http2ServerRequest
很有用。默认值:Http2ServerRequest
。Http2ServerResponse
<http2.Http2ServerResponse> 指定要使用的Http2ServerResponse
类。对于扩展原始Http2ServerResponse
很有用。默认值:Http2ServerResponse
。unknownProtocolTimeout
<数字> 指定服务器在发出'unknownProtocol'
时应等待的超时时间(毫秒)。如果此时套接字尚未被销毁,服务器将销毁它。默认值:10000
。...:可以提供任何
net.createServer()
选项。
返回: <Http2Server>
返回一个 net.Server
实例,该实例创建和管理 Http2Session
实例。
由于没有已知的浏览器支持 未加密的 HTTP/2,因此在与浏览器客户端通信时,需要使用 http2.createSecureServer()
。
import { createServer } from 'node:http2'
// 创建一个未加密的 HTTP/2 服务器。
// 由于没有已知的浏览器支持
// 未加密的 HTTP/2,因此在与浏览器客户端通信时,需要使用 `createSecureServer()`。
const server = createServer()
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200,
})
stream.end('<h1>Hello World</h1>')
})
server.listen(8000)
const http2 = require('node:http2')
// 创建一个未加密的 HTTP/2 服务器。
// 由于没有已知的浏览器支持
// 未加密的 HTTP/2,因此在与浏览器客户端通信时,需要使用 `http2.createSecureServer()`。
const server = http2.createServer()
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200,
})
stream.end('<h1>Hello World</h1>')
})
server.listen(8000)
http2.createSecureServer(options[, onRequestHandler])
[历史]
版本 | 变更 |
---|---|
v13.0.0 | PADDING_STRATEGY_CALLBACK 已等同于提供 PADDING_STRATEGY_ALIGNED ,并且 selectPadding 已移除。 |
v13.3.0, v12.16.0 | 添加了 maxSessionRejectedStreams 选项,默认为 100。 |
v13.3.0, v12.16.0 | 添加了 maxSessionInvalidFrames 选项,默认为 1000。 |
v15.10.0, v14.16.0, v12.21.0, v10.24.0 | 添加了 unknownProtocolTimeout 选项,默认为 10000。 |
v14.4.0, v12.18.0, v10.21.0 | 添加了 maxSettings 选项,默认为 32。 |
v10.12.0 | 添加了 origins 选项,用于在 Http2Session 启动时自动发送 ORIGIN 帧。 |
v8.9.3 | 添加了 maxOutstandingPings 选项,默认为 10。 |
v8.9.3 | 添加了 maxHeaderListPairs 选项,默认为 128 个 header 对。 |
v8.4.0 | 添加于 v8.4.0 |
options
<对象>allowHTTP1
<布尔值> 当设置为true
时,不支持 HTTP/2 的传入客户端连接将降级到 HTTP/1.x。请参阅'unknownProtocol'
事件。请参阅 ALPN 协商。默认值:false
。maxDeflateDynamicTableSize
<数字> 设置用于解压缩 header 字段的最大动态表大小。默认值:4Kib
。maxSettings
<数字> 设置每个SETTINGS
帧的最大设置条目数。允许的最小值为1
。默认值:32
。maxSessionMemory
<数字> 设置Http2Session
允许使用的最大内存。该值以兆字节表示,例如1
等于 1 兆字节。允许的最小值为1
。这是一个基于信用的限制,现有的Http2Stream
可能会导致超出此限制,但在超出此限制时,新的Http2Stream
实例将被拒绝。当前的Http2Stream
会话数、header 压缩表的当前内存使用情况、当前排队待发送的数据以及未确认的PING
和SETTINGS
帧都计入当前限制。默认值:10
。maxHeaderListPairs
<数字> 设置 header 条目的最大数量。这类似于node:http
模块中的server.maxHeadersCount
或request.maxHeadersCount
。最小值为4
。默认值:128
。maxOutstandingPings
<数字> 设置未确认的未完成 ping 的最大数量。默认值:10
。maxSendHeaderBlockLength
<数字> 设置序列化压缩的 header 块的最大允许大小。尝试发送超过此限制的 header 将导致发出'frameError'
事件,并关闭和销毁流。paddingStrategy
<数字> 用于确定HEADERS
和DATA
帧填充量的策略。默认值:http2.constants.PADDING_STRATEGY_NONE
。值可以是以下之一:http2.constants.PADDING_STRATEGY_NONE
: 不应用填充。http2.constants.PADDING_STRATEGY_MAX
: 应用内部实现确定的最大填充量。http2.constants.PADDING_STRATEGY_ALIGNED
: 尝试应用足够的填充,以确保包括 9 字节 header 在内的总帧长度是 8 的倍数。对于每个帧,都存在一个最大允许的填充字节数,该字节数由当前流量控制状态和设置决定。如果此最大值小于确保对齐所需的计算量,则使用最大值,并且总帧长度不一定与 8 字节对齐。peerMaxConcurrentStreams
<数字> 设置远程对等方的最大并发流数,就像已收到SETTINGS
帧一样。如果远程对等方设置了自己的maxConcurrentStreams
值,则将被覆盖。默认值:100
。maxSessionInvalidFrames
<整数> 设置在关闭会话之前允许容忍的最大无效帧数。默认值:1000
。maxSessionRejectedStreams
<整数> 设置在关闭会话之前允许容忍的最大创建时被拒绝的流数。每个拒绝都与一个NGHTTP2_ENHANCE_YOUR_CALM
错误相关联,该错误应告诉对等方不要再打开任何流,因此继续打开流被视为行为不端的对等方的迹象。默认值:100
。settings
<HTTP/2 设置对象> 连接时发送到远程对等方的初始设置。remoteCustomSettings
<数组> 整数值数组确定设置类型,这些类型包含在接收到的 remoteSettings 的customSettings
属性中。有关允许的设置类型的更多信息,请参阅Http2Settings
对象的customSettings
属性。...: 可以提供任何
tls.createServer()
选项。对于服务器,通常需要身份选项(pfx
或key
/cert
)。origins
<字符串数组> 一个 origin 字符串数组,用于在创建新的服务器Http2Session
后立即在ORIGIN
帧中发送。unknownProtocolTimeout
<数字> 指定服务器在发出'unknownProtocol'
事件时应等待的超时时间(以毫秒为单位)。如果那时套接字尚未销毁,服务器将销毁它。默认值:10000
。
返回值: <Http2SecureServer>
返回一个 tls.Server
实例,该实例创建和管理 Http2Session
实例。
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'
const options = {
key: readFileSync('server-key.pem'),
cert: readFileSync('server-cert.pem'),
}
// 创建安全的 HTTP/2 服务器
const server = createSecureServer(options)
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)
const http2 = require('node:http2')
const fs = require('node:fs')
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
}
// 创建安全的 HTTP/2 服务器
const server = http2.createSecureServer(options)
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)
http2.connect(authority[, options][, listener])
[历史]
版本 | 变更 |
---|---|
v13.0.0 | PADDING_STRATEGY_CALLBACK 已等同于提供 PADDING_STRATEGY_ALIGNED ,并且 selectPadding 已被移除。 |
v15.10.0, v14.16.0, v12.21.0, v10.24.0 | 添加了 unknownProtocolTimeout 选项,默认值为 10000。 |
v14.4.0, v12.18.0, v10.21.0 | 添加了 maxSettings 选项,默认值为 32。 |
v8.9.3 | 添加了 maxOutstandingPings 选项,默认限制为 10。 |
v8.9.3 | 添加了 maxHeaderListPairs 选项,默认限制为 128 个头部对。 |
v8.4.0 | 在 v8.4.0 版本中添加 |
authority
<字符串> | <URL> 要连接到的远程 HTTP/2 服务器。这必须采用最小、有效的 URL 格式,包含http://
或https://
前缀、主机名和 IP 端口(如果使用非默认端口)。URL 中的用户身份信息(用户 ID 和密码)、路径、查询字符串和片段详细信息将被忽略。options
<对象>maxDeflateDynamicTableSize
<数字> 设置用于解压缩头部字段的最大动态表大小。默认值:4Kib
。maxSettings
<数字> 设置每个SETTINGS
帧的最大设置条目数。允许的最小值为1
。默认值:32
。maxSessionMemory
<数字> 设置Http2Session
允许使用的最大内存。该值以兆字节数表示,例如1
等于 1 兆字节。允许的最小值为1
。这是一个基于信用的限制,现有的Http2Stream
可能会导致此限制被超过,但当此限制被超过时,新的Http2Stream
实例将被拒绝。当前的Http2Stream
会话数、头部压缩表的当前内存使用情况、当前排队要发送的数据以及未确认的PING
和SETTINGS
帧都计入当前限制。默认值:10
。maxHeaderListPairs
<数字> 设置头部条目的最大数量。这类似于node:http
模块中的server.maxHeadersCount
或request.maxHeadersCount
。最小值为1
。默认值:128
。maxOutstandingPings
<数字> 设置未确认的未完成 ping 的最大数量。默认值:10
。maxReservedRemoteStreams
<数字> 设置客户端在任何给定时间将接受的已预留推送流的最大数量。一旦当前已预留推送流的数量超过此限制,服务器发送的新推送流将自动被拒绝。允许的最小值为 0。允许的最大值为 2-1。负值将此选项设置为允许的最大值。默认值:200
。maxSendHeaderBlockLength
<数字> 设置序列化压缩的头部块的最大允许大小。尝试发送超过此限制的头部将导致发出'frameError'
事件,并且流将被关闭和销毁。paddingStrategy
<数字> 用于确定为HEADERS
和DATA
帧使用多少填充的策略。默认值:http2.constants.PADDING_STRATEGY_NONE
。值可以是:http2.constants.PADDING_STRATEGY_NONE
: 不应用填充。http2.constants.PADDING_STRATEGY_MAX
: 应用内部实现确定的最大填充量。http2.constants.PADDING_STRATEGY_ALIGNED
: 尝试应用足够的填充以确保总帧长度(包括 9 字节的头部)是 8 的倍数。对于每个帧,都有一个由当前流量控制状态和设置确定的最大允许填充字节数。如果此最大值小于确保对齐所需的计算量,则使用最大值,并且总帧长度不一定与 8 字节对齐。peerMaxConcurrentStreams
<数字> 设置远程对等方的最大并发流数,就像已收到SETTINGS
帧一样。如果远程对等方设置了自己的maxConcurrentStreams
值,则将被覆盖。默认值:100
。protocol
<字符串> 要连接的协议,如果未在authority
中设置。值可以是'http:'
或'https:'
。默认值:'https:'
settings
<HTTP/2 设置对象> 连接时发送到远程对等方的初始设置。remoteCustomSettings
<数组> 整数值数组确定设置类型,这些类型包含在收到的 remoteSettings 的CustomSettings
属性中。有关允许的设置类型的更多信息,请参阅Http2Settings
对象的CustomSettings
属性。createConnection
<函数> 一个可选的回调函数,它接收传递给connect
的URL
实例和options
对象,并返回任何Duplex
流,该流将用作此会话的连接。...:可以提供任何
net.connect()
或tls.connect()
选项。unknownProtocolTimeout
<数字> 指定服务器在发出'unknownProtocol'
事件时应等待的超时时间(以毫秒为单位)。如果在此时间内套接字尚未被销毁,则服务器将销毁它。默认值:10000
。
返回值: <ClientHttp2Session>
返回一个 ClientHttp2Session
实例。
import { connect } from 'node:http2'
const client = connect('https://localhost:1234')
/* 使用客户端 */
client.close()
const http2 = require('node:http2')
const client = http2.connect('https://localhost:1234')
/* 使用客户端 */
client.close()
http2.constants
新增于: v8.4.0
RST_STREAM
和 GOAWAY
的错误代码
值 | 名称 | 常量 |
---|---|---|
0x00 | 无错误 | http2.constants.NGHTTP2_NO_ERROR |
0x01 | 协议错误 | http2.constants.NGHTTP2_PROTOCOL_ERROR |
0x02 | 内部错误 | http2.constants.NGHTTP2_INTERNAL_ERROR |
0x03 | 流控制错误 | http2.constants.NGHTTP2_FLOW_CONTROL_ERROR |
0x04 | 设置超时 | http2.constants.NGHTTP2_SETTINGS_TIMEOUT |
0x05 | 流已关闭 | http2.constants.NGHTTP2_STREAM_CLOSED |
0x06 | 帧大小错误 | http2.constants.NGHTTP2_FRAME_SIZE_ERROR |
0x07 | 拒绝流 | http2.constants.NGHTTP2_REFUSED_STREAM |
0x08 | 取消 | http2.constants.NGHTTP2_CANCEL |
0x09 | 压缩错误 | http2.constants.NGHTTP2_COMPRESSION_ERROR |
0x0a | 连接错误 | http2.constants.NGHTTP2_CONNECT_ERROR |
0x0b | 请保持冷静 | http2.constants.NGHTTP2_ENHANCE_YOUR_CALM |
0x0c | 安全性不足 | http2.constants.NGHTTP2_INADEQUATE_SECURITY |
0x0d | 需要 HTTP/1.1 | http2.constants.NGHTTP2_HTTP_1_1_REQUIRED |
当服务器在使用 http2server.setTimeout()
设置的毫秒数内没有活动时,会发出 'timeout'
事件。
http2.getDefaultSettings()
新增于:v8.4.0
- 返回值:<HTTP/2 设置对象>
返回一个包含 Http2Session
实例的默认设置的对象。此方法每次调用都会返回一个新的对象实例,因此返回的实例可以安全地进行修改以供使用。
http2.getPackedSettings([settings])
新增于:v8.4.0
settings
<HTTP/2 设置对象>- 返回值:<Buffer>
返回一个 Buffer
实例,其中包含根据 HTTP/2 规范指定的给定 HTTP/2 设置的序列化表示。这旨在与 HTTP2-Settings
头字段一起使用。
import { getPackedSettings } from 'node:http2'
const packed = getPackedSettings({ enablePush: false })
console.log(packed.toString('base64'))
// 输出:AAIAAAAA
const http2 = require('node:http2')
const packed = http2.getPackedSettings({ enablePush: false })
console.log(packed.toString('base64'))
// 输出:AAIAAAAA
http2.getUnpackedSettings(buf)
Added in: v8.4.0
buf
<Buffer> | <TypedArray> 已打包的设置。- 返回值: <HTTP/2 设置对象>
返回一个 HTTP/2 设置对象,其中包含来自给定 Buffer
的反序列化设置,这些设置由 http2.getPackedSettings()
生成。
http2.performServerHandshake(socket[, options])
Added in: v21.7.0, v20.12.0
socket
<stream.Duplex>options
<Object>- ...: 可以提供任何
http2.createServer()
选项。
- ...: 可以提供任何
返回值: <ServerHttp2Session>
从现有套接字创建 HTTP/2 服务器会话。
http2.sensitiveHeaders
新增于:v15.0.0, v14.18.0
此符号可以作为 HTTP/2 headers 对象的一个属性设置,其值为数组,用于提供被认为是敏感的 headers 列表。更多详情请参见 敏感 headers。
Headers 对象
Headers 在 JavaScript 对象上表示为自身属性。属性键将被序列化为小写。属性值应为字符串(如果不是,则会被强制转换为字符串)或字符串数组(为了发送每个 header 字段的多个值)。
const headers = {
':status': '200',
'content-type': 'text-plain',
ABC: ['has', 'more', 'than', 'one', 'value'],
}
stream.respond(headers)
传递给回调函数的 Header 对象将具有 null
原型。这意味着普通的 JavaScript 对象方法,例如 Object.prototype.toString()
和 Object.prototype.hasOwnProperty()
将无法工作。
对于传入的 headers:
:status
header 会被转换为number
。:status
,:method
,:authority
,:scheme
,:path
,:protocol
,age
,authorization
,access-control-allow-credentials
,access-control-max-age
,access-control-request-method
,content-encoding
,content-language
,content-length
,content-location
,content-md5
,content-range
,content-type
,date
,dnt
,etag
,expires
,from
,host
,if-match
,if-modified-since
,if-none-match
,if-range
,if-unmodified-since
,last-modified
,location
,max-forwards
,proxy-authorization
,range
,referer
,retry-after
,tk
,upgrade-insecure-requests
,user-agent
或x-content-type-options
的重复项将被丢弃。set-cookie
始终为数组。重复项将添加到数组中。- 对于重复的
cookie
headers,其值将用 '; ' 连接在一起。 - 对于所有其他 headers,其值将用 ', ' 连接在一起。
import { createServer } from 'node:http2'
const server = createServer()
server.on('stream', (stream, headers) => {
console.log(headers[':path'])
console.log(headers.ABC)
})
const http2 = require('node:http2')
const server = http2.createServer()
server.on('stream', (stream, headers) => {
console.log(headers[':path'])
console.log(headers.ABC)
})
敏感头部
HTTP2 头部可以标记为敏感的,这意味着 HTTP/2 头部压缩算法永远不会索引它们。对于熵低的并且可能被攻击者认为有价值的头部值(例如 Cookie
或 Authorization
),这样做是有意义的。为此,将头部名称作为数组添加到 [http2.sensitiveHeaders]
属性中:
const headers = {
':status': '200',
'content-type': 'text-plain',
cookie: 'some-cookie',
'other-sensitive-header': 'very secret data',
[http2.sensitiveHeaders]: ['cookie', 'other-sensitive-header'],
}
stream.respond(headers)
对于某些头部,例如 Authorization
和较短的 Cookie
头部,此标志会自动设置。
此属性也设置为接收到的头部。它将包含所有标记为敏感的头部名称,包括自动标记为敏感的那些头部。
设置对象
[历史]
版本 | 变更 |
---|---|
v12.12.0 | maxConcurrentStreams 设置更加严格。 |
v8.9.3 | maxHeaderListSize 设置现在严格执行。 |
v8.4.0 | 新增于:v8.4.0 |
http2.getDefaultSettings()
、http2.getPackedSettings()
、http2.createServer()
、http2.createSecureServer()
、http2session.settings()
、http2session.localSettings
和 http2session.remoteSettings
API 或者返回或者接收一个对象作为输入,该对象定义了 Http2Session
对象的配置设置。这些对象是包含以下属性的普通 JavaScript 对象。
headerTableSize
<数字> 指定用于头部压缩的字节最大数。允许的最小值为 0。允许的最大值为 2-1。默认值:4096
。enablePush
<布尔值> 指定如果要在Http2Session
实例上允许 HTTP/2 推送流,则为true
。默认值:true
。initialWindowSize
<数字> 指定流级别流量控制的发送方初始窗口大小(以字节为单位)。允许的最小值为 0。允许的最大值为 2-1。默认值:65535
。maxFrameSize
<数字> 指定最大帧有效负载的大小(以字节为单位)。允许的最小值为 16384。允许的最大值为 2-1。默认值:16384
。maxConcurrentStreams
<数字> 指定在Http2Session
上允许的最大并发流数。没有默认值,这意味着理论上,在任何给定时间,Http2Session
中可以并发打开 2-1 个流。最小值为 0。允许的最大值为 2-1。默认值:4294967295
。maxHeaderListSize
<数字> 指定将接受的头部列表的最大大小(未压缩的八位字节)。允许的最小值为 0。允许的最大值为 2-1。默认值:65535
。maxHeaderSize
<数字>maxHeaderListSize
的别名。enableConnectProtocol
<布尔值> 指定如果要启用 RFC 8441 定义的“扩展连接协议”,则为true
。此设置仅在服务器发送时才有意义。一旦为给定的Http2Session
启用了enableConnectProtocol
设置,就无法禁用它。默认值:false
。customSettings
<对象> 指定其他设置,但尚未在 node 和底层库中实现。对象的键定义了设置类型的数值(如 RFC 7540 建立的“HTTP/2 SETTINGS”注册表中定义),而值则定义了设置的实际数值。设置类型必须是 1 到 2^16-1 范围内的整数。它不应该是 node 已处理的设置类型,即目前它应该大于 6,尽管这不是错误。值需要是 0 到 2^32-1 范围内的无符号整数。目前,最多支持 10 个自定义设置。它仅支持发送 SETTINGS,或接收服务器或客户端对象的remoteCustomSettings
选项中指定的设置值。如果在未来的 node 版本中对某个设置提供了原生支持,请不要将customSettings
机制与原生处理的设置的接口混合使用。
设置对象上的所有其他属性都会被忽略。
错误处理
使用 node:http2
模块时,可能会出现几种类型的错误情况:
验证错误发生在传入不正确的参数、选项或设置值时。这些错误总是通过同步 throw
报告。
状态错误发生在错误时间尝试执行操作时(例如,在流关闭后尝试向其发送数据)。这些错误将通过同步 throw
或 Http2Stream
、Http2Session
或 HTTP/2 服务器对象的 'error'
事件报告,具体取决于错误发生的位置和时间。
内部错误发生在 HTTP/2 会话意外失败时。这些错误将通过 Http2Session
或 HTTP/2 服务器对象的 'error'
事件报告。
协议错误发生在违反各种 HTTP/2 协议约束时。这些错误将通过同步 throw
或 Http2Stream
、Http2Session
或 HTTP/2 服务器对象的 'error'
事件报告,具体取决于错误发生的位置和时间。
头部名称和值中的无效字符处理
HTTP/2 实现对 HTTP 头部名称和值中无效字符的处理比 HTTP/1 实现更加严格。
头部字段名称不区分大小写,并且严格地以小写字符串的形式在网络上传输。Node.js 提供的 API 允许头部名称设置为混合大小写字符串(例如 Content-Type
),但在传输时会将其转换为小写(例如 content-type
)。
头部字段名称必须仅包含以下 ASCII 字符之一或多个:a
-z
,A
-Z
,0
-9
,!
,#
,$
,%
,&
,'
,*
,+
,-
,.
,^
,_
,```(反引号),|
和~
。
在 HTTP 头部字段名称中使用无效字符将导致流关闭并报告协议错误。
头部字段值处理更宽松,但不应包含换行符或回车符,并且应限于 US-ASCII 字符,符合 HTTP 规范的要求。
客户端上的推送流
要在客户端接收推送流,请为 ClientHttp2Session
上的 'stream'
事件设置一个监听器:
import { connect } from 'node:http2'
const client = connect('http://localhost')
client.on('stream', (pushedStream, requestHeaders) => {
pushedStream.on('push', responseHeaders => {
// 处理响应头
})
pushedStream.on('data', chunk => {
/* 处理推送的数据 */
})
})
const req = client.request({ ':path': '/' })
const http2 = require('node:http2')
const client = http2.connect('http://localhost')
client.on('stream', (pushedStream, requestHeaders) => {
pushedStream.on('push', responseHeaders => {
// 处理响应头
})
pushedStream.on('data', chunk => {
/* 处理推送的数据 */
})
})
const req = client.request({ ':path': '/' })
支持 CONNECT
方法
CONNECT
方法用于允许将 HTTP/2 服务器用作 TCP/IP 连接的代理。
一个简单的 TCP 服务器:
import { createServer } from 'node:net'
const server = createServer(socket => {
let name = ''
socket.setEncoding('utf8')
socket.on('data', chunk => (name += chunk))
socket.on('end', () => socket.end(`hello ${name}`))
})
server.listen(8000)
const net = require('node:net')
const server = net.createServer(socket => {
let name = ''
socket.setEncoding('utf8')
socket.on('data', chunk => (name += chunk))
socket.on('end', () => socket.end(`hello ${name}`))
})
server.listen(8000)
一个 HTTP/2 CONNECT 代理:
import { createServer, constants } from 'node:http2'
const { NGHTTP2_REFUSED_STREAM, NGHTTP2_CONNECT_ERROR } = constants
import { connect } from 'node:net'
const proxy = createServer()
proxy.on('stream', (stream, headers) => {
if (headers[':method'] !== 'CONNECT') {
// 只接受 CONNECT 请求
stream.close(NGHTTP2_REFUSED_STREAM)
return
}
const auth = new URL(`tcp://${headers[':authority']}`)
// 最好验证主机名和端口是否为此代理应该连接到的内容。
const socket = connect(auth.port, auth.hostname, () => {
stream.respond()
socket.pipe(stream)
stream.pipe(socket)
})
socket.on('error', error => {
stream.close(NGHTTP2_CONNECT_ERROR)
})
})
proxy.listen(8001)
const http2 = require('node:http2')
const { NGHTTP2_REFUSED_STREAM } = http2.constants
const net = require('node:net')
const proxy = http2.createServer()
proxy.on('stream', (stream, headers) => {
if (headers[':method'] !== 'CONNECT') {
// 只接受 CONNECT 请求
stream.close(NGHTTP2_REFUSED_STREAM)
return
}
const auth = new URL(`tcp://${headers[':authority']}`)
// 最好验证主机名和端口是否为此代理应该连接到的内容。
const socket = net.connect(auth.port, auth.hostname, () => {
stream.respond()
socket.pipe(stream)
stream.pipe(socket)
})
socket.on('error', error => {
stream.close(http2.constants.NGHTTP2_CONNECT_ERROR)
})
})
proxy.listen(8001)
一个 HTTP/2 CONNECT 客户端:
import { connect, constants } from 'node:http2'
const client = connect('http://localhost:8001')
// 对于 CONNECT 请求,必须不要指定 ':path' 和 ':scheme' 头,否则会抛出错误。
const req = client.request({
':method': 'CONNECT',
':authority': 'localhost:8000',
})
req.on('response', headers => {
console.log(headers[constants.HTTP2_HEADER_STATUS])
})
let data = ''
req.setEncoding('utf8')
req.on('data', chunk => (data += chunk))
req.on('end', () => {
console.log(`服务器说:${data}`)
client.close()
})
req.end('Jane')
const http2 = require('node:http2')
const client = http2.connect('http://localhost:8001')
// 对于 CONNECT 请求,必须不要指定 ':path' 和 ':scheme' 头,否则会抛出错误。
const req = client.request({
':method': 'CONNECT',
':authority': 'localhost:8000',
})
req.on('response', headers => {
console.log(headers[http2.constants.HTTP2_HEADER_STATUS])
})
let data = ''
req.setEncoding('utf8')
req.on('data', chunk => (data += chunk))
req.on('end', () => {
console.log(`服务器说:${data}`)
client.close()
})
req.end('Jane')
扩展的 CONNECT
协议
RFC 8441 定义了 HTTP/2 的“扩展 CONNECT 协议”扩展,可用于使用 CONNECT
方法作为其他通信协议(例如 WebSockets)的隧道来引导 Http2Stream
的使用。
HTTP/2 服务器通过使用 enableConnectProtocol
设置来启用扩展 CONNECT 协议的使用:
import { createServer } from 'node:http2'
const settings = { enableConnectProtocol: true }
const server = createServer({ settings })
const http2 = require('node:http2')
const settings = { enableConnectProtocol: true }
const server = http2.createServer({ settings })
一旦客户端从服务器收到指示可以使用的扩展 CONNECT 的 SETTINGS
帧,它就可以发送使用 ':protocol'
HTTP/2 伪标头的 CONNECT
请求:
import { connect } from 'node:http2'
const client = connect('http://localhost:8080')
client.on('remoteSettings', settings => {
if (settings.enableConnectProtocol) {
const req = client.request({ ':method': 'CONNECT', ':protocol': 'foo' })
// ...
}
})
const http2 = require('node:http2')
const client = http2.connect('http://localhost:8080')
client.on('remoteSettings', settings => {
if (settings.enableConnectProtocol) {
const req = client.request({ ':method': 'CONNECT', ':protocol': 'foo' })
// ...
}
})
兼容性 API
兼容性 API 的目标是在使用 HTTP/2 时提供与 HTTP/1 类似的开发者体验,从而使开发同时支持 HTTP/1 和 HTTP/2 的应用程序成为可能。此 API 仅针对 HTTP/1 的 公共 API。但是许多模块使用内部方法或状态,而这些 不受支持,因为它是一个完全不同的实现。
以下示例使用兼容性 API 创建 HTTP/2 服务器:
import { createServer } from 'node:http2'
const server = createServer((req, res) => {
res.setHeader('Content-Type', 'text/html')
res.setHeader('X-Foo', 'bar')
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('ok')
})
const http2 = require('node:http2')
const server = http2.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html')
res.setHeader('X-Foo', 'bar')
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('ok')
})
要创建混合 HTTPS 和 HTTP/2 服务器,请参阅 ALPN 协商 部分。不支持从非 TLS HTTP/1 服务器升级。
HTTP/2 兼容性 API 由 Http2ServerRequest
和 Http2ServerResponse
组成。它们旨在与 HTTP/1 保持 API 兼容性,但它们并没有隐藏协议之间的差异。例如,HTTP 代码的状态消息将被忽略。
ALPN 协商
ALPN 协商允许在同一个套接字上同时支持 HTTPS 和 HTTP/2。req
和 res
对象可以是 HTTP/1 或 HTTP/2,应用程序必须限制自身使用 HTTP/1 的公共 API,并检测是否可以使用 HTTP/2 的更高级功能。
以下示例创建一个支持这两种协议的服务器:
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'
const cert = readFileSync('./cert.pem')
const key = readFileSync('./key.pem')
const server = createSecureServer({ cert, key, allowHTTP1: true }, onRequest).listen(8000)
function onRequest(req, res) {
// 检测是 HTTPS 请求还是 HTTP/2
const {
socket: { alpnProtocol },
} = req.httpVersion === '2.0' ? req.stream.session : req
res.writeHead(200, { 'content-type': 'application/json' })
res.end(
JSON.stringify({
alpnProtocol,
httpVersion: req.httpVersion,
})
)
}
const { createSecureServer } = require('node:http2')
const { readFileSync } = require('node:fs')
const cert = readFileSync('./cert.pem')
const key = readFileSync('./key.pem')
const server = createSecureServer({ cert, key, allowHTTP1: true }, onRequest).listen(4443)
function onRequest(req, res) {
// 检测是 HTTPS 请求还是 HTTP/2
const {
socket: { alpnProtocol },
} = req.httpVersion === '2.0' ? req.stream.session : req
res.writeHead(200, { 'content-type': 'application/json' })
res.end(
JSON.stringify({
alpnProtocol,
httpVersion: req.httpVersion,
})
)
}
'request'
事件在 HTTPS 和 HTTP/2 上的工作方式相同。
类: http2.Http2ServerRequest
新增于: v8.4.0
- 继承自: <stream.Readable>
Http2ServerRequest
对象由 http2.Server
或 http2.SecureServer
创建,并作为第一个参数传递给 'request'
事件。它可以用来访问请求状态、头部和数据。
事件: 'aborted'
新增于: v8.4.0
当 Http2ServerRequest
实例在通信过程中异常中止时,会发出 'aborted'
事件。
只有当 Http2ServerRequest
的可写端尚未结束时,才会发出 'aborted'
事件。
事件: 'close'
新增于: v8.4.0
指示底层的 Http2Stream
已关闭。与 'end'
一样,此事件每个响应只发生一次。
request.aborted
新增于: v10.1.0
如果请求已被中止,则 request.aborted
属性将为 true
。
request.authority
新增于:v8.4.0
请求授权伪头部字段。因为 HTTP/2 允许请求设置 :authority
或 host
,此值如果存在则来自 req.headers[':authority']
。否则,它来自 req.headers['host']
。
request.complete
新增于:v12.10.0
如果请求已完成、中止或销毁,则 request.complete
属性将为 true
。
request.connection
新增于:v8.4.0
自 v13.0.0 起已弃用
[稳定性:0 - 已弃用]
稳定性:0 稳定性:0 - 已弃用。请使用 request.socket
。
参见 request.socket
。
request.destroy([error])
新增于: v8.4.0
error
<Error>
调用接收 Http2ServerRequest
的 Http2Stream
上的 destroy()
方法。如果提供了 error
,则会发出 'error'
事件,并将 error
作为参数传递给该事件上的任何监听器。
如果流已被销毁,则此方法不会执行任何操作。
request.headers
新增于: v8.4.0
请求/响应头对象。
键值对,包含头名称和值。头名称都小写。
// 打印类似以下内容:
//
// { 'user-agent': 'curl/7.22.0',
// host: '127.0.0.1:8000',
// accept: '*/*' }
console.log(request.headers)
参见 HTTP/2 头对象。
在 HTTP/2 中,请求路径、主机名、协议和方法表示为以 :
字符为前缀的特殊头 (例如 ':path'
)。这些特殊头将包含在 request.headers
对象中。必须注意不要无意中修改这些特殊头,否则可能会发生错误。例如,从请求中删除所有头将导致错误:
removeAllHeaders(request.headers)
assert(request.url) // 失败,因为 :path 头已被删除
request.httpVersion
新增于: v8.4.0
对于服务器请求,客户端发送的 HTTP 版本。对于客户端响应,连接到的服务器的 HTTP 版本。返回 '2.0'
。
同时 message.httpVersionMajor
是第一个整数,message.httpVersionMinor
是第二个整数。
request.method
新增于: v8.4.0
请求方法,以字符串形式表示。只读。例如:'GET'
,'DELETE'
。
request.rawHeaders
新增于: v8.4.0
原始请求/响应报头列表,完全按照接收到的方式显示。
键和值在同一个列表中。它不是一个元组列表。因此,偶数偏移量是键值,奇数偏移量是关联的值。
报头名称不转换为小写,并且不合并重复项。
// 打印类似以下内容:
//
// [ 'user-agent',
// 'this is invalid because there can be only one',
// 'User-Agent',
// 'curl/7.22.0',
// 'Host',
// '127.0.0.1:8000',
// 'ACCEPT',
// '*/*' ]
console.log(request.rawHeaders)
request.rawTrailers
新增于:v8.4.0
原始请求/响应尾部键值对,与接收到的完全一致。仅在 'end'
事件中填充。
request.scheme
新增于:v8.4.0
请求方案伪头部字段,指示目标 URL 的方案部分。
request.setTimeout(msecs, callback)
新增于:v8.4.0
msecs
<number>callback
<Function>- 返回值: <http2.Http2ServerRequest>
将 Http2Stream
的超时值设置为 msecs
。如果提供了回调函数,则将其添加到响应对象的 'timeout'
事件的监听器中。
如果未向请求、响应或服务器添加 'timeout'
监听器,则 Http2Stream
在超时时会被销毁。如果为请求、响应或服务器的 'timeout'
事件分配了处理程序,则必须显式处理超时的套接字。
request.socket
新增于:v8.4.0
返回一个 Proxy
对象,它充当 net.Socket
(或 tls.TLSSocket
),但会根据 HTTP/2 逻辑应用 getter、setter 和方法。
destroyed
、readable
和 writable
属性将从 request.stream
获取并设置。
destroy
、emit
、end
、on
和 once
方法将调用 request.stream
。
setTimeout
方法将调用 request.stream.session
。
pause
、read
、resume
和 write
将抛出代码为 ERR_HTTP2_NO_SOCKET_MANIPULATION
的错误。有关更多信息,请参见 Http2Session
和套接字。
所有其他交互将直接路由到套接字。使用 TLS 支持,使用 request.socket.getPeerCertificate()
获取客户端的身份验证详细信息。
request.stream
新增于:v8.4.0
支持请求的 Http2Stream
对象。
request.trailers
新增于:v8.4.0
请求/响应尾部对象。仅在 'end'
事件中填充。
request.url
新增于:v8.4.0
请求 URL 字符串。这仅包含实际 HTTP 请求中存在的 URL。如果请求为:
GET /status?name=ryan HTTP/1.1 Accept: text/plain
那么 request.url
将为:
'/status?name=ryan'
要将 url 解析为其各个部分,可以使用 new URL()
:
$ node
> new URL('/status?name=ryan', 'http://example.com')
URL {
href: 'http://example.com/status?name=ryan',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/status',
search: '?name=ryan',
searchParams: URLSearchParams { 'name' => 'ryan' },
hash: ''
}
类: http2.Http2ServerResponse
新增于: v8.4.0
- 继承自: <Stream>
此对象由 HTTP 服务器内部创建,而非用户创建。它作为第二个参数传递给 'request'
事件。
事件: 'close'
新增于: v8.4.0
指示底层 Http2Stream
在调用或能够刷新 response.end()
之前已终止。
事件: 'finish'
新增于: v8.4.0
在响应已发送时发出。更具体地说,当响应头和正文的最后一部分已移交给 HTTP/2 多路复用以通过网络传输时,就会发出此事件。它并不意味着客户端已经接收到了任何内容。
此事件之后,将不再为此响应对象发出任何事件。
response.addTrailers(headers)
新增于: v8.4.0
headers
<Object>
此方法向响应添加 HTTP 尾部标头(消息末尾的标头)。
尝试设置包含无效字符的标头字段名称或值将导致抛出 TypeError
。
response.appendHeader(name, value)
新增于: v21.7.0, v20.12.0
向头部对象追加单个头部值。
如果值为数组,则等同于多次调用此方法。
如果头部之前没有值,则等同于调用 response.setHeader()
。
尝试设置包含无效字符的头部字段名称或值将导致抛出 TypeError
错误。
// 返回的头部包括 "set-cookie: a" 和 "set-cookie: b"
const server = http2.createServer((req, res) => {
res.setHeader('set-cookie', 'a')
res.appendHeader('set-cookie', 'b')
res.writeHead(200)
res.end('ok')
})
response.connection
新增于: v8.4.0
自 v13.0.0 起已弃用
[稳定性: 0 - 已弃用]
稳定性: 0 - 已弃用。请使用 response.socket
。
参见 response.socket
。
response.createPushResponse(headers, callback)
[历史记录]
版本 | 变更 |
---|---|
v18.0.0 | 将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK 。 |
v8.4.0 | 新增于: v8.4.0 |
headers
<HTTP/2 Headers 对象> 描述报头的对象callback
<函数>http2stream.pushStream()
完成后调用一次,或者当创建推送的Http2Stream
尝试失败或被拒绝时调用,或者在调用http2stream.pushStream()
方法之前Http2ServerRequest
的状态已关闭时调用err
<错误>res
<http2.Http2ServerResponse> 新创建的Http2ServerResponse
对象
使用给定的报头调用 http2stream.pushStream()
,如果成功,则将给定的 Http2Stream
包装在新建的 Http2ServerResponse
上作为回调参数。当 Http2ServerRequest
关闭时,回调将使用错误 ERR_HTTP2_INVALID_STREAM
调用。
response.end([data[, encoding]][, callback])
[历史]
版本 | 变更 |
---|---|
v10.0.0 | 此方法现在返回对 ServerResponse 的引用。 |
v8.4.0 | v8.4.0 版本新增 |
此方法向服务器发出信号,表明所有响应头和正文都已发送;服务器应将此消息视为已完成。必须在每个响应上调用 response.end()
方法。
如果指定了 data
,则等效于调用 response.write(data, encoding)
然后调用 response.end(callback)
。
如果指定了 callback
,则当响应流结束时将调用它。
response.finished
新增于:v8.4.0
自以下版本起已弃用:v13.4.0, v12.16.0
[稳定性:0 - 已弃用]
稳定性:0 稳定性:0 - 已弃用。请使用 response.writableEnded
。
指示响应是否已完成的布尔值。初始值为 false
。response.end()
执行后,其值将变为 true
。
response.getHeader(name)
新增于:v8.4.0
读取已排队但尚未发送到客户端的标头。名称不区分大小写。
const contentType = response.getHeader('content-type')
response.getHeaderNames()
新增于:v8.4.0
- 返回值: <string[]>
返回一个数组,包含当前输出报头的唯一名称。所有报头名称都小写。
response.setHeader('Foo', 'bar')
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz'])
const headerNames = response.getHeaderNames()
// headerNames === ['foo', 'set-cookie']
response.getHeaders()
新增于:v8.4.0
- 返回值: <Object>
返回当前输出报头的浅拷贝。由于使用了浅拷贝,数组值可以在不额外调用各种与报头相关的 http 模块方法的情况下进行更改。返回对象的键是报头名称,值是相应的报头值。所有报头名称都小写。
response.getHeaders()
方法返回的对象不原型继承自 JavaScript Object
。这意味着典型的 Object
方法,例如 obj.toString()
、obj.hasOwnProperty()
等未定义且将无法工作。
response.setHeader('Foo', 'bar')
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz'])
const headers = response.getHeaders()
// headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }
response.hasHeader(name)
新增于:v8.4.0
如果传出报头中当前已设置了由 name
标识的报头,则返回 true
。报头名称匹配不区分大小写。
const hasContentType = response.hasHeader('content-type')
response.headersSent
新增于:v8.4.0
如果报头已发送,则为 true
,否则为 false
(只读)。
response.removeHeader(name)
新增于:v8.4.0
name
<string>
移除已排队等待隐式发送的报头。
response.removeHeader('Content-Encoding')
response.req
新增于:v15.7.0
对原始 HTTP2 request
对象的引用。
response.sendDate
新增于:v8.4.0
当值为 true
时,如果响应头中不存在 Date
头,则会自动生成并发送 Date
头。默认为 true
。
仅在测试时才应禁用此选项;HTTP 要求响应中包含 Date
头。
response.setHeader(name, value)
新增于:v8.4.0
为隐式头设置单个头值。如果此头已存在于待发送的头中,则其值将被替换。在此处使用字符串数组可以发送具有相同名称的多个头。
response.setHeader('Content-Type', 'text/html; charset=utf-8')
或
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript'])
尝试设置包含无效字符的头字段名称或值将导致抛出 TypeError
异常。
当使用 response.setHeader()
设置头时,它们将与传递给 response.writeHead()
的任何头合并,传递给 response.writeHead()
的头具有优先级。
// 返回 content-type = text/plain
const server = http2.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.setHeader('X-Foo', 'bar')
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('ok')
})
response.setTimeout(msecs[, callback])
新增于:v8.4.0
msecs
<number>callback
<Function>- 返回值: <http2.Http2ServerResponse>
将 Http2Stream
的超时值设置为 msecs
。如果提供了回调函数,则将其添加到响应对象的 'timeout'
事件的监听器中。
如果未向请求、响应或服务器添加 'timeout'
监听器,则 Http2Stream
在超时时将被销毁。如果为请求、响应或服务器的 'timeout'
事件分配了处理程序,则必须显式处理超时的套接字。
response.socket
新增于:v8.4.0
返回一个 Proxy
对象,它充当 net.Socket
(或 tls.TLSSocket
),但会根据 HTTP/2 逻辑应用 getter、setter 和方法。
destroyed
、readable
和 writable
属性将从 response.stream
获取和设置。
destroy
、emit
、end
、on
和 once
方法将在 response.stream
上调用。
setTimeout
方法将在 response.stream.session
上调用。
pause
、read
、resume
和 write
将抛出带有代码 ERR_HTTP2_NO_SOCKET_MANIPULATION
的错误。有关更多信息,请参阅 Http2Session
和套接字。
所有其他交互都将直接路由到套接字。
import { createServer } from 'node:http2'
const server = createServer((req, res) => {
const ip = req.socket.remoteAddress
const port = req.socket.remotePort
res.end(`Your IP address is ${ip} and your source port is ${port}.`)
}).listen(3000)
const http2 = require('node:http2')
const server = http2
.createServer((req, res) => {
const ip = req.socket.remoteAddress
const port = req.socket.remotePort
res.end(`Your IP address is ${ip} and your source port is ${port}.`)
})
.listen(3000)
response.statusCode
新增于: v8.4.0
当使用隐式头部(没有显式调用response.writeHead()
)时,此属性控制当头部被刷新时将发送给客户端的状态码。
response.statusCode = 404
响应头部发送到客户端后,此属性指示已发送的状态码。
response.statusMessage
新增于: v8.4.0
HTTP/2 (RFC 7540 8.1.2.4) 不支持状态消息。它返回一个空字符串。
response.stream
新增于: v8.4.0
支持响应的Http2Stream
对象。
response.writableEnded
新增于: v12.9.0
调用response.end()
后为 true
。此属性并不指示数据是否已刷新,为此请改用writable.writableFinished
。
response.write(chunk[, encoding][, callback])
新增于:v8.4.0
如果调用此方法且未调用response.writeHead()
,则它将切换到隐式标头模式并刷新隐式标头。
这将发送响应正文的一部分。可以多次调用此方法以提供正文的连续部分。
在node:http
模块中,当请求是 HEAD 请求时,响应正文将被省略。同样,204
和304
响应必须不包含消息正文。
chunk
可以是字符串或缓冲区。如果chunk
是字符串,则第二个参数指定如何将其编码为字节流。默认情况下,encoding
为'utf8'
。当此数据块被刷新时,将调用callback
。
这是原始的 HTTP 正文,与可能使用的更高级的多部分正文编码无关。
第一次调用response.write()
时,它将把缓冲的标头信息和正文的第一块数据发送到客户端。第二次调用response.write()
时,Node.js 假设数据将被流式传输,并单独发送新数据。也就是说,响应缓冲到正文的第一块数据。
如果所有数据都成功刷新到内核缓冲区,则返回true
。如果所有或部分数据已排队到用户内存中,则返回false
。缓冲区再次可用时,将发出'drain'
事件。
response.writeContinue()
新增于:v8.4.0
向客户端发送状态码 100 Continue
,指示应该发送请求正文。请参阅 Http2Server
和 Http2SecureServer
上的 'checkContinue'
事件。
response.writeEarlyHints(hints)
新增于:v18.11.0
hints
<Object>
向客户端发送状态码 103 Early Hints
和 Link 头部,指示用户代理可以预加载/预连接链接的资源。hints
是一个对象,包含要与早期提示消息一起发送的头部值。
示例
const earlyHintsLink = '</styles.css>; rel=preload; as=style'
response.writeEarlyHints({
link: earlyHintsLink,
})
const earlyHintsLinks = ['</styles.css>; rel=preload; as=style', '</scripts.js>; rel=preload; as=script']
response.writeEarlyHints({
link: earlyHintsLinks,
})
response.writeHead(statusCode[, statusMessage][, headers])
[历史]
版本 | 变更 |
---|---|
v11.10.0, v10.17.0 | 从 writeHead() 返回 this 以允许与 end() 链式调用。 |
v8.4.0 | 新增于:v8.4.0 |
statusCode
<number>statusMessage
<string>headers
<Object> | <Array>- 返回值: <http2.Http2ServerResponse>
向请求发送响应头部。状态码是一个 3 位数字的 HTTP 状态码,例如 404
。最后一个参数 headers
是响应头部。
返回 Http2ServerResponse
的引用,以便可以链式调用。
为了与 HTTP/1 兼容,可以将人类可读的 statusMessage
作为第二个参数传递。但是,由于 statusMessage
在 HTTP/2 中没有意义,因此该参数不会有任何作用,并且会发出进程警告。
const body = 'hello world'
response.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/plain; charset=utf-8',
})
Content-Length
以字节为单位,而不是字符。可以使用 Buffer.byteLength()
API 来确定给定编码中字节的数量。在出站消息中,Node.js 不会检查 Content-Length
和正在传输的正文长度是否相等。但是,在接收消息时,Node.js 会在 Content-Length
与实际有效负载大小不匹配时自动拒绝消息。
在调用 response.end()
之前,此方法最多可以在一条消息上调用一次。
如果在调用此方法之前调用了 response.write()
或 response.end()
,则将计算隐式/可变头部并调用此函数。
当使用 response.setHeader()
设置头部时,它们将与传递给 response.writeHead()
的任何头部合并,传递给 response.writeHead()
的头部将优先。
// 返回 content-type = text/plain
const server = http2.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.setHeader('X-Foo', 'bar')
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('ok')
})
尝试设置包含无效字符的头部字段名称或值将导致抛出 TypeError
。
收集 HTTP/2 性能指标
可以使用 Performance Observer API 收集每个 Http2Session
和 Http2Stream
实例的基本性能指标。
import { PerformanceObserver } from 'node:perf_hooks'
const obs = new PerformanceObserver(items => {
const entry = items.getEntries()[0]
console.log(entry.entryType) // 输出 'http2'
if (entry.name === 'Http2Session') {
// Entry 包含关于 Http2Session 的统计信息
} else if (entry.name === 'Http2Stream') {
// Entry 包含关于 Http2Stream 的统计信息
}
})
obs.observe({ entryTypes: ['http2'] })
const { PerformanceObserver } = require('node:perf_hooks')
const obs = new PerformanceObserver(items => {
const entry = items.getEntries()[0]
console.log(entry.entryType) // 输出 'http2'
if (entry.name === 'Http2Session') {
// Entry 包含关于 Http2Session 的统计信息
} else if (entry.name === 'Http2Stream') {
// Entry 包含关于 Http2Stream 的统计信息
}
})
obs.observe({ entryTypes: ['http2'] })
PerformanceEntry
的 entryType
属性将等于 'http2'
。
PerformanceEntry
的 name
属性将等于 'Http2Stream'
或 'Http2Session'
之一。
如果 name
等于 Http2Stream
,则 PerformanceEntry
将包含以下附加属性:
bytesRead
<number> 此Http2Stream
接收到的DATA
帧字节数。bytesWritten
<number> 此Http2Stream
发送的DATA
帧字节数。id
<number> 关联的Http2Stream
的标识符。timeToFirstByte
<number>PerformanceEntry
的startTime
和接收第一个DATA
帧之间经过的毫秒数。timeToFirstByteSent
<number>PerformanceEntry
的startTime
和发送第一个DATA
帧之间经过的毫秒数。timeToFirstHeader
<number>PerformanceEntry
的startTime
和接收第一个 header 之间经过的毫秒数。
如果 name
等于 Http2Session
,则 PerformanceEntry
将包含以下附加属性:
bytesRead
<number> 此Http2Session
接收的字节数。bytesWritten
<number> 此Http2Session
发送的字节数。framesReceived
<number>Http2Session
接收到的 HTTP/2 帧数。framesSent
<number>Http2Session
发送的 HTTP/2 帧数。maxConcurrentStreams
<number>Http2Session
生命周期中同时打开的最大流数。pingRTT
<number> 发送PING
帧和接收其确认之间经过的毫秒数。仅当在Http2Session
上发送了PING
帧时才存在。streamAverageDuration
<number> 所有Http2Stream
实例的平均持续时间(以毫秒为单位)。streamCount
<number>Http2Session
处理的Http2Stream
实例数。type
<string>'server'
或'client'
,用于标识Http2Session
的类型。
关于 :authority
和 host
的说明
HTTP/2 要求请求包含 :authority
伪头部或 host
头部。直接构建 HTTP/2 请求时,优先使用 :authority
;从 HTTP/1 转换时(例如,在代理中),使用 host
。
如果不存在 :authority
,兼容性 API 会回退到 host
。更多信息,请参见 request.authority
。但是,如果您不使用兼容性 API(或直接使用 req.headers
),则需要自行实现任何回退行为。