稳定性:2 - 稳定
此模块包含客户端和服务器,可通过 require('node:http') (CommonJS) 或 import * as http from 'node:http' (ES 模块) 导入。
Node.js 中的 HTTP 接口旨在支持该协议的许多传统上难以使用的功能。 特别是大型的、可能分块编码的消息。该接口谨慎地从不缓冲整个请求或响应,以便 用户能够流式传输数据。
HTTP 消息头由如下对象表示:
{ "content-length": "123",
"content-type": "text/plain",
"connection": "keep-alive",
"host": "example.com",
"accept": "*/*" }键为小写。值不会被修改。
为了支持各种可能的 HTTP 应用,Node.js HTTP API 非常底层。它仅处理流处理和消息 解析。它将消息解析为头和主体,但不 解析实际的头或主体。
详见 message.headers 了解如何处理重复头的详情。
接收到的原始头信息保留在 rawHeaders
属性中,它是一个 [key, value, key2, value2, ...] 数组。例如,
前面的消息头对象可能具有如下 rawHeaders
列表:
[ "ConTent-Length", "123456",
"content-LENGTH", "123",
"content-type", "text/plain",
"CONNECTION", "keep-alive",
"Host", "example.com",
"accepT", "*/*" ]<Object><boolean>Connection
头的
keep-alive
值混淆。使用 agent 时始终发送
Connection: keep-alive
头,除非显式指定了
Connection
头,或者当
keepAlive
和
maxSockets
选项分别设置为
false
和
Infinity
时,在这种情况下
将使用
Connection: close
。
默认值:
false
。<number>keepAlive
选项时,指定
TCP Keep-Alive 数据包的 [初始延迟][]。
当
keepAlive
选项为
false
或
undefined
时忽略。
默认值:
1000
。<number>keep-alive: timeout=...
提示中减去的毫秒数。
此缓冲区有助于确保 agent 在服务器之前稍微关闭套接字,
减少在即将被服务器关闭的套接字上发送请求的几率。
默认值:
1000
。<number>maxSockets
值。
如果主机尝试打开超过
maxSockets
的连接,
额外的请求将进入待处理请求队列,并在现有连接终止时
进入活动连接状态。
这确保在任何时间点,给定主机最多有
maxSockets
个活动连接。
默认值:
Infinity
。<number>Infinity
。<number>keepAlive
设置为
true
时相关。
默认值:
256
。<string>'fifo'
或
'lifo'
。
两种调度策略的主要区别在于
'lifo'
选择最近使用的套接字,而
'fifo'
选择
最久未使用的套接字。
在每秒请求率较低的情况下,
'lifo'
调度
将降低选择可能因不活动而被服务器关闭的套接字的风险。
在每秒请求率较高的情况下,
'fifo'
调度将最大化打开套接字的数量,
而
'lifo'
调度将使其保持尽可能低。
默认值:
'lifo'
。<number><Object>
|
<undefined>undefined<string>
|
<undefined><string>
|
<undefined><string>
|
<undefined><string>
|
<undefined>HTTP_PROXY
相同。如果两者都设置,
http_proxy
优先。<string>
|
<undefined>HTTPS_PROXY
相同。如果两者都设置,
https_proxy
优先。<string>
|
<undefined>NO_PROXY
相同。如果两者都设置,
no_proxy
优先。<number>80
。<string>'http:'
。socket.connect() 中的 options 也受支持。
当连接被客户端或服务器关闭时,它会从连接池中移除。连接池中的任何未使用套接字都会被取消引用(unref),以便在没有未完成请求时不会让 Node.js 进程继续运行。(参见 socket.unref())。
import { Agent, request } from 'node:http';
const keepAliveAgent = new Agent({ keepAlive: true });
options.agent = keepAliveAgent;
request(options, onResponseCallback);使用 agent: false 可避免某个请求复用连接。
socket.connect() 中的 options 也受支持。
要配置其中任何一项,必须创建自定义 http.Agent 实例。
import { Agent, request } from 'node:http';
const keepAliveAgent = new Agent({ keepAlive: true });
options.agent = keepAliveAgent;
request(options, onResponseCallback);生成一个用于 HTTP 请求的套接字/流。
默认情况下,此函数的行为与 net.createConnection() 完全相同,
同步返回创建的套接字。签名中的可选 callback 参数不被此默认实现使用。
然而,自定义 agent 可以重写此方法以提供更大的灵活性,
例如异步创建套接字。当重写 createConnection 时:
- 同步套接字创建:重写的方法可以直接返回 套接字/流。
- 异步套接字创建:重写的方法可以接受
callback并将创建的套接字/流传递给它(例如,callback(null, newSocket))。 如果在套接字创建期间发生错误,应将其作为第一个 参数传递给callback(例如,callback(err))。
agent 将使用 options 和此内部 callback 调用提供的 createConnection 函数。
agent 提供的 callback 的签名为 (err, stream)。
当 socket 从请求中分离并可由
Agent 持久化时调用。默认行为是:
socket.setKeepAlive(true, this.keepAliveMsecs);
socket.unref();
return true;此方法可被特定的 Agent 子类重写。如果此
方法返回假值,套接字将被销毁,而不是被持久化
以供下一个请求使用。
socket 参数可以是 <net.Socket> 的实例,即
<stream.Duplex> 的子类。
当 socket 因 keep-alive 选项而被持久化后附加到 request 时调用。
默认行为是:
socket.ref();此方法可被特定的 Agent 子类重写。
socket 参数可以是 <net.Socket> 的实例,即
<stream.Duplex> 的子类。
通常不需要这样做。但是,如果使用启用了
keepAlive 的 agent,则最好在不再需要时显式关闭
agent。否则,
套接字可能会在服务器终止它们之前保持打开很长时间。
当 keepAlive 启用时,包含 agent 当前等待使用的套接字数组的对象。
请勿修改。
freeSockets 列表中的套接字将在 'timeout' 时自动销毁并
从数组中移除。
获取一组请求选项的唯一名称,以确定连接
是否可以复用。对于 HTTP agent,这将返回
host:port:localAddress 或 host:port:localAddress:family。对于 HTTPS agent,
名称包括 CA、cert、ciphers 和其他决定套接字可复用性的
HTTPS/TLS 特定选项。
默认值为 256。对于启用了 keepAlive 的 agent,此值设置将保持处于空闲状态的套接字最大数量。
默认设置为 Infinity。确定 agent
每个源可以打开多少个并发套接字。源是 agent.getName() 的返回值。
默认设置为 Infinity。确定 agent
可以打开多少个并发套接字。与 maxSockets 不同,此参数适用于所有源。
包含尚未分配给 套接字的请求队列的对象。请勿修改。
包含 agent 当前使用的套接字数组的对象。 请勿修改。
此对象在内部创建并从 http.request() 返回。它表示一个_进行中_的请求,其头部已入队。头部仍然可以使用 setHeader(name, value)、getHeader(name)、removeHeader(name) API 进行可变操作。实际头部将随第一个数据块一起发送,或在调用 request.end() 时发送。
要获取响应,请为请求对象添加 'response' 监听器。当收到响应头部时,'response' 将从请求对象触发。'response' 事件执行时带有一个参数,该参数是 http.IncomingMessage 的实例。
在 'response' 事件期间,可以向响应对象添加监听器;特别是监听 'data' 事件。
如果没有添加 'response' 处理程序,则响应将被完全丢弃。但是,如果添加了 'response' 事件处理程序,则必须消费来自响应对象的数据,要么在有 'readable' 事件时调用 response.read(),要么添加 'data' 处理程序,要么调用 .resume() 方法。在数据被消费之前,'end' 事件不会触发。此外,在数据被读取之前,它将消耗内存,最终可能导致 '进程内存溢出' 错误。
为了向后兼容,只有在注册了 'error' 监听器的情况下,res 才会触发 'error'。
设置 Content-Length 头部以限制响应体大小。如果 response.strictContentLength 设置为 true,Content-Length 头部值不匹配将导致抛出 Error,标识为 code: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH'。
Content-Length 值应为字节数,而非字符数。使用 Buffer.byteLength() 来确定主体的字节长度。
当请求被客户端中止时触发。此事件仅在第一次调用 abort() 时触发。
每当服务器响应带有 CONNECT 方法的请求时触发。如果没有监听此事件,接收 CONNECT 方法的客户端的连接将被关闭。
除非用户指定了 <net.Socket> 以外的 socket 类型,否则保证此事件会传递一个 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类。
演示如何监听 'connect' 事件的客户端和服务器配对示例:
import { createServer, request } from 'node:http';
import { connect } from 'node:net';
import { URL } from 'node:url';
// 创建一个 HTTP 隧道代理
const proxy = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
// 连接到源服务器
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
// 现在代理正在运行
proxy.listen(1337, '127.0.0.1', () => {
// 向隧道代理发出请求
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80',
};
const req = request(options);
req.end();
req.on('connect', (res, socket, head) => {
console.log('已连接!');
// 通过 HTTP 隧道发出请求
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});当服务器发送 1xx 中间响应时触发(不包括 101 升级)。此事件的监听器将接收一个对象,其中包含 HTTP 版本、状态码、状态消息、键值头部对象,以及包含原始头部名称及其各自值的数组。
import { request } from 'node:http';
const options = {
host: '127.0.0.1',
port: 8080,
path: '/length_request',
};
// 发出请求
const req = request(options);
req.end();
req.on('information', (info) => {
console.log(`在主响应之前收到信息:${info.statusCode}`);
});101 升级状态不会触发此事件,因为它们打破了传统的 HTTP 请求/响应链,例如 web sockets、原地 TLS 升级或 HTTP 2.0。要接收 101 升级通知,请改为监听 'upgrade' 事件。
当收到此请求的响应时触发。此事件仅触发一次。
除非用户指定了 <net.Socket> 以外的 socket 类型,否则保证此事件会传递一个 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类。
每当服务器响应带有升级的请求时触发。如果没有监听此事件且响应状态码为 101 Switching Protocols,接收升级头部的客户端的连接将被关闭。
除非用户指定了 <net.Socket> 以外的 socket 类型,否则保证此事件会传递一个 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类。
演示如何监听 'upgrade' 事件的客户端服务器配对示例。
import http from 'node:http';
import process from 'node:process';
// 创建一个 HTTP 服务器
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
server.on('upgrade', (req, stream, head) => {
stream.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n');
stream.pipe(stream); // Echo
});
// 现在服务器正在运行
server.listen(1337, '127.0.0.1', () => {
// 发出请求
const options = {
port: 1337,
host: '127.0.0.1',
headers: {
'Connection': 'Upgrade',
'Upgrade': 'websocket',
},
};
const req = http.request(options);
req.end();
req.on('upgrade', (res, stream, upgradeHead) => {
console.log('已升级!');
stream.end();
process.exit(0);
});
});将请求标记为中止。调用此方法将导致响应中的剩余数据被丢弃并且 socket 被销毁。
- 类型:
<boolean>
如果请求已被中止,则 request.aborted 属性将为 true。
参见 request.socket。
完成发送请求。如果主体的任何部分未发送,它将把它们冲刷到流中。如果请求是分块的,这将发送终止符 '0\r\n\r\n'。
如果指定了 data,则相当于调用 request.write(data, encoding) 后跟 [request.end(callback)]。
如果指定了 callback,它将在请求流完成时被调用。
销毁请求。可选择触发 'error' 事件,并触发 'close' 事件。调用此方法会导致响应中的剩余数据被丢弃,并在使用了 socket 时销毁 socket;否则在可能的情况下将其返回到相应的 Agent 池。
- 类型:
<boolean>
在调用 request.destroy() 后为 true。
- 类型:
<boolean>
如果调用了 request.end(),request.finished 属性将为 true。如果请求是通过 http.get() 发起的,request.end() 将被自动调用。
出于效率原因,Node.js 通常缓冲请求头部,直到调用 request.end() 或写入第一块请求数据。然后它尝试将请求头部和数据打包到单个 TCP 数据包中。
这通常是理想的(它节省了一次 TCP 往返),但当第一块数据直到可能更晚的时候才发送时则不然。request.flushHeaders() 绕过优化并启动请求。
读取请求上的一个头部。名称不区分大小写。返回值的类型取决于提供给 request.setHeader() 的参数。
request.setHeader('content-type', 'text/html');
request.setHeader('Content-Length', Buffer.byteLength(body));
request.setHeader('Cookie', ['type=ninja', 'language=javascript']);
const contentType = request.getHeader('Content-Type');
// 'contentType' 是 'text/html'
const contentLength = request.getHeader('Content-Length');
// 'contentLength' 是 number 类型
const cookie = request.getHeader('Cookie');
// 'cookie' 是 string[] 类型返回一个包含当前传出头部唯一名称的数组。所有头部名称均为小写。
request.setHeader('Foo', 'bar');
request.setHeader('Cookie', ['foo=bar', 'bar=baz']);
const headerNames = request.getHeaderNames();
// headerNames === ['foo', 'cookie']返回当前传出头部的浅拷贝。由于使用了浅拷贝,数组值可能会被变更,而无需额外调用各种头部相关的 http 模块方法。返回对象的键是头部名称,值是相应的头部值。所有头部名称均为小写。
request.getHeaders() 方法返回的对象 不 原型继承自 JavaScript Object。这意味着典型的 Object 方法(如 obj.toString()、obj.hasOwnProperty() 等)未定义且 将无法工作】【。
request.setHeader('Foo', 'bar');
request.setHeader('Cookie', ['foo=bar', 'bar=baz']);
const headers = request.getHeaders();
// headers === { foo: 'bar', 'cookie': ['foo=bar', 'bar=baz'] }返回一个包含当前传出原始头部唯一名称的数组。头部名称返回时保留其设置的确切大小写形式。
request.setHeader('Foo', 'bar');
request.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);
const headerNames = request.getRawHeaderNames();
// headerNames === ['Foo', 'Set-Cookie']如果由 name 标识的头部当前已设置在传出头部中,则返回 true。头部名称匹配不区分大小写。
const hasContentType = request.hasHeader('content-type');限制最大响应头部数量。如果设置为 0,则不应用限制。
移除已在头部对象中定义的头部。
request.removeHeader('Content-Type');当通过启用了 keep-alive 的 agent 发送请求时,底层套接字可能会被重用。但如果服务器在不当时机关闭连接,客户端可能会遇到 'ECONNRESET' 错误。
import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });
// 服务器默认有 5 秒的 keep-alive 超时
http
.createServer((req, res) => {
res.write('hello\n');
res.end();
})
.listen(3000);
setInterval(() => {
// 使用一个 keep-alive agent
http.get('http://localhost:3000', { agent }, (res) => {
res.on('data', (data) => {
// 什么都不做
});
});
}, 5000); // 每 5 秒发送一次请求,以便更容易触发空闲超时通过标记请求是否重用了套接字,我们可以据此进行自动错误重试。
import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });
function retriableRequest() {
const req = http
.get('http://localhost:3000', { agent }, (res) => {
// ...
})
.on('error', (err) => {
// 检查是否需要重试
if (req.reusedSocket && err.code === 'ECONNRESET') {
retriableRequest();
}
});
}
retriableRequest();为头部对象设置单个头部值。如果此头部已存在于待发送的头部中,其值将被替换。此处使用字符串数组来发送多个具有相同名称的头部。非字符串值将未经修改地存储。因此,request.getHeader() 可能返回非字符串值。但是,非字符串值将被转换为字符串以便网络传输。
request.setHeader('Content-Type', 'application/json');或
request.setHeader('Cookie', ['type=ninja', 'language=javascript']);当值为字符串时,如果它包含 latin1 编码之外的字符,将抛出异常。
如果需要在值中传递 UTF-8 字符,请使用 RFC 8187 标准对值进行编码。
const filename = 'Rock 🎵.txt';
request.setHeader('Content-Disposition', `attachment; filename*=utf-8''${encodeURIComponent(filename)}`);一旦将套接字分配给此请求并且连接已建立,便会调用 socket.setNoDelay()。
一旦将 socket 分配给此请求并完成连接,socket.setKeepAlive() 将被调用。
一旦将 socket 分配给此请求并完成连接,socket.setTimeout() 将被调用。
指向底层 socket 的引用。通常用户不希望访问此属性。特别是,由于协议解析器附加到 socket 的方式,socket 不会触发 'readable' 事件。
import http from 'node:http';
const options = {
host: 'www.google.com',
};
const req = http.get(options);
req.end();
req.once('response', (res) => {
const ip = req.socket.localAddress;
const port = req.socket.localPort;
console.log(`你的 IP 地址是 ${ip},源端口是 ${port}。`);
// 消费响应对象
});除非用户指定了 <net.Socket> 以外的 socket 类型,否则保证此属性是 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类。
在调用 request.end() 后为 true。此属性不指示数据是否已冲刷,为此请改用 request.writableFinished。
如果在 'finish' 事件触发之前,所有数据已刷写到底层系统,则为 true。
发送一块主体数据。此方法可以调用多次。如果未设置 Content-Length,数据将自动以 HTTP 分块传输编码进行编码,以便服务器知道数据何时结束。将添加 Transfer-Encoding: chunked 头部。必须调用 request.end() 来完成发送请求。
encoding 参数是可选的,仅当 chunk 是字符串时适用。默认为 'utf8'。
callback 参数是可选的,当这块数据被冲刷时将被调用,但仅当这块数据非空时。
如果整个数据成功冲刷到内核缓冲区,则返回 true。如果全部或部分数据入队到用户内存,则返回 false。当缓冲区再次空闲时,将触发 'drain'。
当 write 函数使用空字符串或缓冲区调用时,它什么都不做并等待更多输入。
- 继承自:
<net.Server>
每当收到带有 HTTP Expect: 100-continue 的请求时触发。
如果未监听此事件,服务器将会自动根据需要以 100 Continue 作出响应。
处理此事件时,如果客户端应继续发送请求主体,则需要调用 response.writeContinue();如果客户端不应继续发送请求主体,则需要生成适当的 HTTP 响应(例如 400 错误请求)。
一旦该事件被触发并处理,'request' 事件将不会再触发。
每当收到带有 HTTP Expect 头部且其值不是 100-continue 的请求时触发。如果未监听此事件,服务器将会自动根据需要以 417 Expectation Failed 作出响应。
一旦该事件被触发并处理,'request' 事件将不会再触发。
如果客户端连接触发了 'error' 事件,就会转发到这里。
此事件的监听器负责关闭/销毁底层 socket。例如,使用自定义 HTTP 响应更优雅地关闭 socket,而不是突然中断连接,可能会更合适。处理程序在返回之前必须关闭或销毁该 socket。
除非用户指定了 <net.Socket> 以外的 socket 类型,否则此事件保证会传递 <net.Socket> 类的实例,
它是 <stream.Duplex> 的子类。
默认行为是尝试使用 HTTP '400 Bad Request' 关闭 socket,或者在发生 HPE_HEADER_OVERFLOW 错误时使用 HTTP '431 Request Header Fields Too Large'。如果 socket 不可写,或者当前附加的 http.ServerResponse 的头部已经发送,则会立即销毁它。
socket 是发生错误的 net.Socket 对象。
import http from 'node:http';
const server = http.createServer((req, res) => {
res.end();
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);当发生 'clientError' 事件时,不存在 request 或 response
对象,因此发送的任何 HTTP 响应(包括响应头和有效载荷)
都必须直接写入 socket 对象。需要特别注意,确保该响应是格式正确的 HTTP 响应消息。
err 是 Error 的一个实例,并且有两个额外字段:
bytesParsed:Node.js 可能已正确解析的请求数据包字节;rawPacket:当前请求的原始数据包。
在某些情况下,客户端已经收到了响应,和/或套接字
已经被销毁,例如 ECONNRESET 错误的情况。在尝试向套接字发送数据之前,
最好先检查它是否仍然可写。
server.on('clientError', (err, socket) => {
if (err.code === 'ECONNRESET' || !socket.writable) {
return;
}
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});每当客户端请求 HTTP CONNECT 方法时触发。如果没有监听此事件,请求 CONNECT 方法的客户端连接将被关闭。
除非用户指定的套接字类型不是 <net.Socket>,否则此事件保证传入 <net.Socket> 类的实例,而该类是 <stream.Duplex> 的子类。
在此事件触发后,请求的套接字将不再有 'data' 事件监听器,这意味着需要对其进行绑定,才能处理发送到服务器的数据。
当建立新的 TCP 流时触发。socket 通常是 net.Socket 类型的对象。通常不应直接访问此事件。特别是,由于协议解析器附加到套接字的方式,套接字不会触发 'readable' 事件。socket 也可以通过 request.socket 访问。
用户可以显式触发此事件,以将连接注入 HTTP 服务器。在这种情况下,可以传入任何 Duplex 流。
如果在此处调用 socket.setTimeout(),且 server.keepAliveTimeout 不为零,则在套接字处理完一个请求后,超时将被替换为 server.keepAliveTimeout。
除非用户指定的套接字类型不是 <net.Socket>,否则此事件保证传入 <net.Socket> 类的实例,而该类是 <stream.Duplex> 的子类。
当套接字上的请求数量达到 server.maxRequestsPerSocket 阈值时,服务器将放弃新的请求,改为触发 'dropRequest' 事件,并向客户端发送 503。
每当收到请求时都会触发。在一个连接中可能会有多个请求(在 HTTP Keep-Alive 连接的情况下)。
每当接受客户端的 HTTP 升级请求时触发。默认情况下,所有 HTTP 升级请求都会被忽略(也就是说,只会触发常规的 'request'`` 事件,从而保持正常的 HTTP 请求/响应流程),除非你监听此事件;在这种情况下,它们都会被接受(也就是说,会触发 'upgrade'事件,之后通信必须直接通过原始流继续)。你可以使用服务器的shouldUpgradeCallback` 选项更精确地控制此行为。
监听此事件是可选的;客户端不能强制更改协议。
如果 shouldUpgradeCallback 接受了升级,但没有注册任何事件处理器,套接字将被销毁,导致客户端立即关闭连接。
在极少数情况下,如果请求包含主体,那么主体将被正常解析并与升级后的流分离,而原始流数据只有在主体完成后才会开始。为确保在等待读取请求主体时不会阻塞对流的读取,对流的任何读取都会自动开始让请求主体流动。如果你想读取请求主体,请务必在开始读取升级后的流之前将其完成(也就是说,附加一个 'data' 监听器)。
流参数通常是请求所使用的 <net.Socket> 实例,但在某些情况下(例如存在请求主体时),它可能是一个双工流。如有必要,你可以通过 request.socket 访问请求的底层原始连接;只要用户没有指定其他套接字类型,该对象就保证是 <net.Socket> 的实例。
停止服务器接受新连接,并关闭所有连接到该服务器且既不发送请求也不等待响应的连接。
参见 net.Server.close().
const http = require('node:http');
const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});
server.listen(8000);
// 10 秒后关闭服务器
setTimeout(() => {
server.close(() => {
console.log('8000 端口上的服务器已成功关闭');
});
}, 10000);这是一种强制关闭所有连接的方法,应谨慎使用。 与
server.close一起使用时,建议在调用server.close之后再调用此方法,以避免在此调用与server.close调用之间创建新连接而产生竞争条件。
const http = require('node:http');
const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: '你好,世界!',
}));
});
server.listen(8000);
// 10 秒后关闭服务器
setTimeout(() => {
server.close(() => {
console.log('8000 端口上的服务器已成功关闭');
});
// 关闭所有连接以确保服务器成功关闭
server.closeAllConnections();
}, 10000);从 Node.js 19.0.0 开始,不再需要将此方法与
server.close结合调用来回收keep-alive连接。使用它不会有坏处, 并且可以用于确保与需要支持 19.0.0 之前版本的库和应用程序保持向后兼容。 与server.close一起使用时,建议在调用server.close之后再调用此方法,以避免在本次调用和server.close调用之间创建新连接而导致的竞争条件。
const http = require('node:http');
const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});
server.listen(8000);
// 10 秒后关闭服务器
setTimeout(() => {
server.close(() => {
console.log('端口 8000 上的服务器已成功关闭');
});
// 关闭空闲连接,例如 keep-alive 连接。一旦剩余的活动连接结束,服务器将关闭
server.closeIdleConnections();
}, 10000);限制解析器等待接收完整 HTTP 标头的时间。
如果超时,服务器会返回 408 状态码,而不会将请求转发给请求监听器,然后关闭连接。
必须将其设置为非零值(例如 120 秒),以防在服务器未部署在 反向代理之后时遭受潜在的拒绝服务攻击。
限制传入标头的最大数量。如果设置为 0,则不应用限制。
设置接收客户端整个请求的超时时间(毫秒)。
如果超时,服务器会返回 408 状态码,而不会将请求转发给请求监听器,然后关闭连接。
必须将其设置为非零值(例如 120 秒),以防在服务器未部署在 反向代理之后时遭受潜在的拒绝服务攻击。
设置套接字的超时时间,如果发生超时,则在
Server 对象上发出 'timeout' 事件,并将该套接字作为参数传递。
如果 Server 对象上存在 'timeout' 事件监听器,那么它会
以超时套接字作为参数被调用。
默认情况下,服务器不会让套接字超时。但是,如果为服务器的 'timeout' 事件
分配了回调函数,则必须显式处理超时。
套接字在关闭 keep alive 连接之前所能处理的最大请求数。
值为 0 将禁用该限制。
达到限制后,它会将 Connection 标头值设置为 close,但实际上不会关闭连接。限制达到后发送的后续请求将收到 503 Service Unavailable 响应。
套接字在被视为超时之前处于非活动状态的毫秒数。
值为 0 将禁用传入连接的超时行为。
套接字超时逻辑在连接时设置,因此更改此值 只会影响到服务器的新连接,不会影响任何现有连接。
服务器在写入最后一条响应后, 在销毁套接字之前,需要等待额外传入数据的毫秒数。
此超时值与
server.keepAliveTimeoutBuffer 选项配合使用,以以下方式确定实际
套接字超时:
socketTimeout = keepAliveTimeout + keepAliveTimeoutBuffer
如果服务器在 keep-alive 超时触发之前收到额外数据,
它会重置常规空闲超时,即 server.timeout。
值为 0 将禁用传入连接上的 keep-alive 超时行为。
值为 0 会让 HTTP 服务器的行为类似于 Node.js 8.0.0 之前的版本,
那时没有 keep-alive 超时。
套接字超时逻辑在建立连接时就已设置,因此更改此值 只会影响到服务器上的新连接,不会影响任何现有连接。
要添加到
server.keepAliveTimeout 的额外缓冲时间,用于延长内部
套接字超时。
此缓冲有助于通过将套接字超时相对于公布的 keep-alive 超时略微
增加,从而减少连接重置(ECONNRESET)错误。
此选项仅适用于新的传入连接。
此对象由 HTTP 服务器内部创建,而非由用户创建。它作为第二个参数传递给 'request' 事件。
此方法将 HTTP 尾部头(消息末尾的头)添加到响应中。
仅当响应使用分块编码时,尾部头 才会 被发出;如果不是(例如,如果请求是 HTTP/1.0),它们将被静默丢弃。
HTTP 要求发送 Trailer 头才能发出尾部头,其值中包含头部字段列表。例如,
response.writeHead(200, { 'Content-Type': 'text/plain',
'Trailer': 'Content-MD5' });
response.write(fileData);
response.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' });
response.end();尝试设置包含无效字符的头部字段名或值将导致抛出 TypeError.
参见 response.socket.
此方法向服务器发出信号,表明所有响应头部和主体都已发送;服务器应认为此消息已完成。每个响应都必须调用 response.end() 方法。
如果指定了 data,其效果类似于调用 response.write(data, encoding) 后跟 [response.end(callback)]。
如果指定了 callback,它将在响应流完成时调用。
- 类型:
<boolean>
如果已调用 response.end(),则 response.finished 属性将为 true。
读取已排队但尚未发送给客户端的头部。名称不区分大小写。返回值的类型取决于提供给 response.setHeader() 的参数。
response.setHeader('Content-Type', 'text/html');
response.setHeader('Content-Length', Buffer.byteLength(body));
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
const contentType = response.getHeader('content-type');
// contentType 是 'text/html'
const contentLength = response.getHeader('Content-Length');
// contentLength 是 number 类型
const setCookie = response.getHeader('set-cookie');
// setCookie 是 string[] 类型返回一个包含当前传出头部唯一名称的数组。所有头部名称均为小写。
response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);
const headerNames = response.getHeaderNames();
// headerNames === ['foo', 'set-cookie']返回当前传出头部的浅拷贝。由于使用的是浅拷贝,数组值可以在不调用各种头部相关的 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'] }如果由 name 标识的头部当前设置在传出头部中,则返回 true。头部名称匹配不区分大小写。
const hasContentType = response.hasHeader('content-type');布尔值。只读。如果已发送标头,则为 true;否则为 false。
移除即将隐式发送的头部。
response.removeHeader('Content-Encoding');对原始 HTTP request 对象的引用。
当为 true 时,如果头部中尚未存在 Date 头部,则会自动生成并在响应中发送 Date 头部。默认为 true。
这应仅用于测试;大多数 HTTP 响应都需要 Date 头部(详见 RFC 9110 第 6.6.1 节)。
Returns the response object.
Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name. Non-string values will be stored without modification. Therefore, response.getHeader() may return non-string values. However, non-string values will be converted to strings for network transmission. Returns the same response object to the caller to enable chaining.
response.setHeader('Content-Type', 'text/html');or
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);Attempting to set a header field name or value containing invalid characters will throw a TypeError.
When headers are set using response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() taking precedence.
// returns content-type = text/plain
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Foo', 'bar');
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('ok');
});If response.writeHead() method is called and this method is not called, it will directly write the provided header values to the network channel without internal caching, and response.getHeader() for that header will not produce the expected result. If you want to incrementally populate headers for future retrieval and modification, use response.setHeader() instead of response.writeHead().
将 Socket 的超时时间设置为 msecs。如果提供了 callback,则它会作为监听器添加到响应对象的 'timeout' 事件上。
如果未将 'timeout' 监听器添加到请求、响应或服务器,则套接字在超时时会被销毁。如果处理程序已分配给请求、响应或服务器的 'timeout' 事件,则必须显式处理超时的套接字。
对底层 socket 的引用。通常用户不希望访问此属性。特别是,由于协议解析器附加到 socket 的方式,socket 不会发出 'readable' 事件。在 response.end() 之后,该属性被置空。
import http from 'node:http';
const server = http.createServer((req, res) => {
const ip = res.socket.remoteAddress;
const port = res.socket.remotePort;
res.end(`您的 IP 地址是 ${ip},源端口是 ${port}。`);
}).listen(3000);除非用户指定了 <net.Socket> 以外的 socket 类型,否则此属性保证是 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类。
当使用隐式头部(未显式调用 response.writeHead())时,此属性控制在刷新头部时发送给客户端的状态码。
response.statusCode = 404;在响应头部发送给客户端后,此属性指示发出的状态码。
当使用隐式头部(未显式调用 response.writeHead())时,此属性控制在刷新头部时发送给客户端的状态消息。如果此属性保持为 undefined,则将使用该状态码的标准消息。
response.statusMessage = 'Not found';在响应头部发送给客户端后,此属性指示发出的状态消息。
如果设置为 true,Node.js 将检查 Content-Length 头部值与主体大小(以字节为单位)是否相等。Content-Length 头部值不匹配将导致抛出 Error,标识为 code: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH'.
在调用 response.end() 之后为 true。此属性不表示数据是否已刷新;为此请使用 response.writableFinished.
如果所有数据都已刷新到底层系统,则在 'finish' 事件发出之前立即为 true。
如果调用了此方法且尚未调用 response.writeHead(),它将切换到隐式头部模式并刷新隐式头部。
这会发送响应主体的一块。可以多次调用此方法以提供主体的连续部分。
如果在 createServer 中将 rejectNonStandardBodyWrites 设置为 true,则当请求方法或响应状态不支持内容时,不允许写入主体。如果尝试为 HEAD 请求写入主体或作为 204 或 304 响应的一部分写入主体,则会抛出代码为 ERR_HTTP_BODY_NOT_ALLOWED 的同步 Error。
chunk 可以是字符串或 buffer。如果 chunk 是字符串,则第二个参数指定如何将其编码为字节流。当这块数据被刷新时,将调用 callback。
这是原始 HTTP 主体,与可能使用的更高级的多部分主体编码无关。
第一次调用 response.write() 时,它将把缓冲的头部信息和第一块主体发送给客户端。第二次调用 response.write() 时,Node.js 假设数据将被流式传输,并单独发送新数据。也就是说,响应被缓冲到主体的第一块。
如果整个数据成功刷新到内核缓冲区,则返回 true。如果全部或部分数据排队在用户内存中,则返回 false。当缓冲区再次空闲时,将发出 'drain'。
向客户端发送带有 Link 头部的 HTTP/1.1 103 Early Hints 消息,指示用户代理可以预加载/预连接链接的资源。hints 是一个对象,包含要随 early hints 消息发送的头部值。可选的 callback 参数将在写入响应消息时调用。
示例
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,
'x-trace-id': '用于诊断的 id',
});
const earlyHintsCallback = () => console.log('早期提示消息已发送');
response.writeEarlyHints({
'link': earlyHintsLinks,
}, earlyHintsCallback);向请求发送响应头。状态码是 3 位 HTTP 状态码,如 404。最后一个参数 headers 是响应头。可选地,可以将人类可读的 statusMessage 作为第二个参数给出。
headers 可以是一个 Array,其中键和值在同一列表中。它 不是 元组列表。因此,偶数偏移量是键值,奇数偏移量是关联值。数组格式与 request.rawHeaders 相同。
返回对 ServerResponse 的引用,以便调用可以链式进行。
const body = 'hello world';
response
.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/plain',
})
.end(body);此方法在消息上只能调用一次,且必须在调用 response.end() 之前调用。
如果在调用此之前调用了 response.write() 或 response.end(),则将计算隐式/可变头部并调用此函数。
当使用 response.setHeader() 设置头部时,它们将与传递给 response.writeHead() 的任何头部合并,传递给 response.writeHead() 的头部具有优先级。
如果调用了此方法且未调用 response.setHeader(),它将直接把提供的头部值写入网络通道而不内部缓存,并且对该头部的 response.getHeader() 将不会产生预期结果。如果希望逐步填充头部以便将来检索和修改,请使用 response.setHeader()。
// 返回 content-type = text/plain
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Foo', 'bar');
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('ok');
});Content-Length 以字节为单位读取,而不是字符。使用 Buffer.byteLength() 确定主体的字节长度。Node.js 将检查 Content-Length 与已传输的主体长度是否相等。
尝试设置包含无效字符的头部字段名或值将导致抛出 TypeError.
向客户端发送任意的 HTTP/1.1 1xx 信息性响应。这是 response.writeContinue()、response.writeProcessing() 和 response.writeEarlyHints() 的通用等价形式,并且可以在最终响应之前调用多次。在最终响应头部已发送后(通过 response.writeHead() 或隐式头部发送),调用此方法将抛出 ERR_HTTP_HEADERS_SENT。
客户端通过 http.ClientRequest 上的 'information' 事件接收这些响应。
response.writeInformation(110, { 'X-Progress': '50%' });IncomingMessage 对象由 http.Server 或 http.ClientRequest 创建,并分别作为第一个参数传递给 'request' 和 'response' 事件。它可用于访问响应状态、头部和数据。
与其 socket 值(<stream.Duplex> 的子类)不同,IncomingMessage 本身继承自 <stream.Readable> 并单独创建,用于解析和发出传入的 HTTP 头部和负载,因为底层 socket 可能在保持活动的情况下被多次重用。
当请求被中止时发出。
- 类型:
<boolean>
如果请求已被中止,message.aborted 属性将为 true。
如果完整的 HTTP 消息已被接收并成功解析,message.complete 属性将为 true。
此属性特别有用,可用于确定在连接终止之前客户端或服务器是否完全传输了消息:
const req = http.request({
host: '127.0.0.1',
port: 8080,
method: 'POST',
}, (res) => {
res.resume();
res.on('end', () => {
if (!res.complete)
console.error(
'连接在消息仍在发送时被终止');
});
});message.socket 的别名。
在接收 IncomingMessage 的 socket 上调用 destroy()。如果提供了 error,则在 socket 上发出 'error' 事件,并将 error 作为参数传递给该事件的任何监听器。
请求/响应头部对象。
头部名称和值的键值对。头部名称为小写。
// 打印类似以下内容:
//
// { 'user-agent': 'curl/7.22.0',
// host: '127.0.0.1:8000',
// accept: '*/*' }
console.log(request.headers);原始头部中的重复项根据头部名称按以下方式处理:
age、authorization、content-length、content-type、etag、expires、from、host、if-modified-since、if-unmodified-since、last-modified、location、max-forwards、proxy-authorization、referer、retry-after、server或user-agent的重复项将被丢弃。 要允许上述列出的头部重复值被连接,请在http.request()和http.createServer()中使用joinDuplicateHeaders选项。有关更多信息,请参阅 RFC 9110 第 5.3 节。set-cookie始终是一个数组。重复项会被添加到数组中。- 对于重复的
cookie头部,值用;连接在一起。 - 对于所有其他头部,值用
,连接在一起。
类似于 message.headers,但没有连接逻辑,且值始终是字符串数组,即使对于只接收一次的头部也是如此。
// 打印类似以下内容:
//
// { 'user-agent': ['curl/7.22.0'],
// host: ['127.0.0.1:8000'],
// accept: ['*/*'] }
console.log(request.headersDistinct);如果是服务器请求,则为客户端发送的 HTTP 版本。如果是客户端响应,则为所连接服务器的 HTTP 版本。
可能是 '1.1' 或 '1.0'。
此外,message.httpVersionMajor 是第一个整数,message.httpVersionMinor 是第二个整数。
仅对从 http.Server 获得的请求有效。
请求方法,字符串形式。只读。示例:'GET'、'DELETE'。
原始请求/响应头部列表,完全按照接收到的样子。
键和值在同一个列表中。它 不是 元组列表。因此,偶数偏移量是键值,奇数偏移量是关联值。
头部名称不大写,重复项不合并。
// 打印类似以下内容:
//
// [ 'user-agent',
// '这是无效的,因为只能有一个',
// 'User-Agent',
// 'curl/7.22.0',
// 'Host',
// '127.0.0.1:8000',
// 'ACCEPT',
// '*/*' ]
console.log(request.rawHeaders);原始请求/响应尾部键和值,完全按照接收到的样子。仅在 'end' 事件处填充。
调用 message.socket.setTimeout(msecs, callback)。
当底层 socket 关闭或请求被销毁时中止的 <AbortSignal>。该信号在首次访问时惰性创建——对于从未使用此属性的请求,不会分配 <AbortController>。
当客户端在请求中途断开连接时,这对于取消下游异步工作(例如数据库查询或 fetch 调用)非常有用。
import http from 'node:http';
http.createServer(async (req, res) => {
try {
const data = await fetch('https://example.com/api', { signal: req.signal });
res.end(JSON.stringify(await data.json()));
} catch (err) {
if (err.name === 'AbortError') return;
res.statusCode = 500;
res.end('Internal Server Error');
}
}).listen(3000);与连接关联的 net.Socket 对象。
支持 HTTPS 时,使用 request.socket.getPeerCertificate() 获取客户端的身份验证详细信息。
除非用户指定了 <net.Socket> 以外的 socket 类型或在内部设为空,否则此属性保证是 <net.Socket> 类(<stream.Duplex> 的子类)的实例。
仅对从 http.ClientRequest 获得的响应有效。
3 位 HTTP 响应状态码。例如 404。
仅对从 http.ClientRequest 获得的响应有效。
HTTP 响应状态消息(原因短语)。例如 OK 或 Internal Server Error。
请求/响应尾部对象。仅在 'end' 事件处填充。
类似于 message.trailers,但没有连接逻辑,且值始终是字符串数组,即使对于只接收一次的头部也是如此。
仅在 'end' 事件处填充。
仅对从 http.Server 获得的请求有效。
请求 URL 字符串。这仅包含实际 HTTP 请求中存在的 URL。例如以下请求:
GET /status?name=ryan HTTP/1.1
Accept: text/plain要将 URL 解析为其组成部分:
new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);当 request.url 为 '/status?name=ryan' 且 process.env.HOST 为未定义时:
$ node
> new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);
URL {
href: 'http://localhost/status?name=ryan',
origin: 'http://localhost',
protocol: 'http:',
username: '',
password: '',
host: 'localhost',
hostname: 'localhost',
port: '',
pathname: '/status',
search: '?name=ryan',
searchParams: URLSearchParams { 'name' => 'ryan' },
hash: ''
}确保将 process.env.HOST 设置为服务器的主机名,或者考虑完全替换此部分。如果使用 req.headers.host,请确保使用适当的验证,因为客户端可能会指定自定义 Host 头部。
- 继承自:
<Stream>
此类作为 http.ClientRequest 和 http.ServerResponse 的父类。从 HTTP 事务参与者的角度来看,它是一个抽象的传出消息。
将 HTTP 尾部(头部但在消息末尾)添加到消息中。
仅当消息采用分块编码时,才会发出尾部。否则,尾部将被静默丢弃。
HTTP 要求发送 Trailer 头部以发出尾部,其值中包含头部字段名称列表,例如:
message.writeHead(200, { 'Content-Type': 'text/plain',
'Trailer': 'Content-MD5' });
message.write(fileData);
message.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' });
message.end();尝试设置包含无效字符的头部字段名称或值将导致抛出 TypeError。
将单个头部值附加到头部对象。
如果值是数组,则相当于多次调用此方法。
如果该头部之前没有值,则相当于调用 outgoingMessage.setHeader(name, value)。
根据创建客户端请求或服务器时 options.uniqueHeaders 的值,这将导致头部被发送多次,或者单次发送且值用 ; 连接。
销毁消息。一旦 socket 与消息关联并连接,该 socket 也将被销毁。
完成传出消息。如果有任何主体部分未发送,它将把它们刷新到底层系统。如果消息是分块的,它将发送终止块 0\r\n\r\n,并发送尾部(如果有)。
如果指定了 chunk,则相当于调用 outgoingMessage.write(chunk, encoding),然后调用 outgoingMessage.end(callback)。
如果提供了 callback,它将在消息完成时调用(相当于 'finish' 事件的监听器)。
出于效率原因,Node.js 通常缓冲消息头部,直到调用 outgoingMessage.end() 或写入第一块消息数据。然后它尝试将头部和数据打包到单个 TCP 数据包中。
这通常是希望的(它节省了一次 TCP 往返),但当第一块数据直到可能更晚才发送时则不然。outgoingMessage.flushHeaders() 绕过优化并启动消息。
获取给定名称的 HTTP 头部的值。如果未设置该头部,返回值将为 undefined。
返回一个包含当前传出头部唯一名称的数组。所有名称均为小写。
返回当前传出头部的浅拷贝。由于使用的是浅拷贝,数组值可能会被修改,而无需额外调用各种头部相关的 HTTP 模块方法。返回对象的键是头部名称,值是相应的头部值。所有头部名称均为小写。
outgoingMessage.getHeaders() 方法返回的对象不从 JavaScript Object 原型继承。这意味着典型的 Object 方法(如 obj.toString()、obj.hasOwnProperty() 等)未定义且无法工作。
outgoingMessage.setHeader('Foo', 'bar');
outgoingMessage.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);
const headers = outgoingMessage.getHeaders();
// headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }如果由 name 标识的头部当前已设置在传出头部中,则返回 true。头部名称不区分大小写。
const hasContentType = outgoingMessage.hasHeader('content-type');只读。如果已发送头部,则为 true,否则为 false。
调用此方法将抛出 Error,因为 outgoingMessage 是只写流。
移除排队等待隐式发送的头部。
outgoingMessage.removeHeader('Content-Encoding');设置单个头部值。如果该头部已存在于待发送头部中,其值将被替换。使用字符串数组发送多个同名的头部。
为隐式头部设置多个头部值。
headers 必须是 Headers 或 Map 的实例,
如果头部已存在于待发送头部中,
其值将被替换。
const headers = new Headers({ foo: 'bar' });
outgoingMessage.setHeaders(headers);或
const headers = new Map([['foo', 'bar']]);
outgoingMessage.setHeaders(headers);当使用 outgoingMessage.setHeaders() 设置头部时,
它们将与传递给 response.writeHead() 的任何头部合并,
传递给 response.writeHead() 的头部具有优先级。
// 返回 content-type = text/plain
const server = http.createServer((req, res) => {
const headers = new Headers({ 'Content-Type': 'text/html' });
res.setHeaders(headers);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('ok');
});一旦 socket 与消息关联并连接,
socket.setTimeout() 将被调用,msecs 作为第一个参数。
底层 socket 的引用。通常,用户不希望访问此属性。
调用 outgoingMessage.end() 后,此属性将被设为空。
outgoingMessage.cork() 被调用的次数。
如果已调用 outgoingMessage.end(),则为 true。此属性不指示数据是否已刷新。为此,请改用 message.writableFinished。
如果所有数据都已刷新到底层系统,则为 true。
如果已分配,则为底层 socket 的 highWaterMark。否则,为 writable.write() 开始返回 false 时的默认缓冲区级别(16384)。
缓冲字节的数量。
始终为 false。
发送一块主体。此方法可以调用多次。
仅当 chunk 为字符串时,encoding 参数才相关。默认为 'utf8'。
callback 参数是可选的,当这块数据被刷新时将调用它。
如果整个数据成功刷新到内核缓冲区,则返回 true。如果全部或部分数据排队在用户内存中,则返回 false。当缓冲区再次空闲时,将发出 'drain' 事件。
- 类型:
<string>[]
解析器支持的 HTTP 方法列表。
- 类型:
<Object>
所有标准 HTTP 响应状态码及其简短描述的集合。例如,http.STATUS_CODES[404] === '未找到'。<Object>30000
。server.headersTimeout
。
默认值:
60000
。<number>socket
的
readableHighWaterMark
和
writableHighWaterMark
。这会影响
highWaterMark
属性,作用于
IncomingMessage
和
ServerResponse
。
默认值:
参见
stream.getDefaultHighWaterMark()
。<string>insecureHTTPParser: true
)。
不能与
insecureHTTPParser
同时使用。
默认值:
'strict'
。<boolean><http.IncomingMessage>IncomingMessage
类。用于扩展原始的
IncomingMessage
很有用。
默认值:
IncomingMessage
。<boolean><boolean><number>0
。server.keepAliveTimeout
。
默认值:
65000
。<number>--max-http-header-size
的值,适用于由此服务器接收的请求,即
请求头的最大字节长度。
默认值:
16384(16 KiB)。<boolean>true
,则会在接收到新的传入连接后立即
禁用 Nagle 算法的使用。
默认值:
true
。server.requestTimeout
。
默认值:
300000
。<boolean>true
,则会强制服务器
对任何缺少 Host 头部的 HTTP/1.1
请求消息返回 400(错误请求)状态码
(这是规范要求的)。
默认值:
true
。<http.ServerResponse>ServerResponse
类。
用于扩展原始的
ServerResponse
很有用。
默认值:
ServerResponse
。<Function>'upgrade'
事件(如果未注册监听器,
则其套接字将被销毁);而被拒绝的升级将像任何非升级
请求一样触发
'request'
事件。此选项默认为
() => server.listenerCount('upgrade') > 0
。<Array>;
连接。<boolean>true
,则在向一个没有主体的 HTTP 响应
写入时会抛出错误。
默认值:
false
。<boolean>true
,则没有
Content-Length
或
Transfer-Encoding
头部(表示没有主体)的请求将以一个
已结束的主体流初始化,因此它们将永远不会发出任何流事件
(如
'data'
或
'end'
)。你可以使用
req.readableEnded
来检测这种情况。
默认值:
false
。<Function>
返回 http.Server 的新实例。
requestListener 是一个自动
添加到 'request' 事件的函数。
import http from 'node:http';
// 创建一个本地服务器来接收数据
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});
server.listen(8000);由于大多数请求都是没有正文的 GET 请求,Node.js 提供了这个便捷方法。此方法与
http.request() 的唯一区别在于,它默认将方法设置为 GET 并自动调用 req.end()。出于 http.ClientRequest 部分所述的原因,回调必须注意消耗响应数据。
使用单个参数调用 callback,该参数是
http.IncomingMessage 的实例。
JSON 获取示例:
http.get('http://localhost:8000/', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
// Any 2xx status code indicates a successful response, but
// here we're only checking for 200.
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
// Create a local server to receive data
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});
server.listen(8000);- 类型:
<http.Agent>
Agent 的全局实例,用作所有 HTTP 客户端请求的默认值。与默认 Agent 配置不同的是,它启用了 keepAlive 且 timeout 为 5 秒。
- 类型:
<number>
只读属性,指定 HTTP 头部的最大允许大小(字节)。默认为 16 KiB。可使用 --max-http-header-size CLI 选项进行配置。
可以通过传递 maxHeaderSize 选项来覆盖服务器和客户端请求的此设置。<Object><http.Agent>
|
<boolean>Agent
的行为。可能的值:<string>'user:password'
)。<Function>agent
选项时,用于生成套接字/流以供请求使用的函数。这可用于避免仅仅为了覆盖默认的
createConnection
函数而创建自定义
Agent
类。更多详情参见
agent.createConnection()
。任何
Duplex
流都是有效的返回值。<number>Agent
,则为
agent.defaultPort
,否则为
undefined
。<number>host
或
hostname
时使用的 IP 地址族。有效值为
4
或
6
。未指定时,将同时使用 IPv4 和 IPv6。message.rawHeaders
相同。<number>dns.lookup()
提示][]。<string>'localhost'
。<string><string>insecureHTTPParser: true
)。
不能与
insecureHTTPParser
同时使用。
默认:
'strict'
。<boolean><boolean><string><number><Function>dns.lookup()
。<number>--max-http-header-size
值(响应头部的最大长度,以字节为单位)。
默认:
16384(16 KiB)。<string>'GET'
。<string>'/index.html?page=12'
。当请求路径包含非法字符时会抛出异常。目前只会拒绝空格,但未来可能会变化。
默认:
'/'
。
path
中的内容会作为 HTTP 1.1 消息中的
request target
发送。
当
path
是绝对 URL 时,这意味着消息中的请求目标是
absolute form
。
如果接收服务器是代理服务器,服务器通常会将请求转发到请求目标中指定的目的地,并忽略
Host
头部。
用户需要确保
path
、
host
和 Host 头部符合 HTTP 规范中
request target
的要求。
当由于请求通过 [Built-in Proxy Support][] 路由而已知接收服务器是代理服务器时,
http.request
还会在请求的初始构造阶段尽最大努力检查
host
选项或
headers
中的
Host
是否与
path
中的 authority 一致。如果它们不匹配,它会放弃为代理重写请求目标,并在请求构造时抛出错误,不过对于用户之后对头部做的修改则不会再检查。<number>defaultPort
,则使用它,否则为
80
。<string>'http:'
。<boolean>Connection
、
Content-Length
、
Transfer-Encoding
和
Host
。如果设为
false
,则必须手动添加所有必需的头部。
默认值为
true
。<boolean>Host
头部。如果提供此项,将覆盖
setDefaultHeaders
。默认值为
true
。<AbortSignal><string>host
或
port
中的任意一个,则不能使用此项,因为它们指定的是 TCP 套接字。<number><Array>;
连接。<Function>
socket.connect() 中的 options 也受支持。
Node.js 维护每个服务器的多个连接以发出 HTTP 请求。此函数允许透明地发出请求。
url 可以是字符串或 URL 对象。如果 url 是字符串,它将使用 new URL() 自动解析。如果它是 URL 对象,它将自动转换为普通的 options 对象。
如果同时指定了 url 和 options,则对象会被合并,options 属性优先。
可选的 callback 参数将作为 'response' 事件的一次性监听器添加。
http.request() 返回 http.ClientRequest 类的一个实例。ClientRequest 实例是一个可写流。如果需要使用 POST 请求上传文件,则写入 ClientRequest 对象。
import http from 'node:http';
import { Buffer } from 'node:buffer';
const postData = JSON.stringify({
'msg': 'Hello World!',
});
const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
};
const req = http.request(options, (res) => {
console.log(`状态码:${res.statusCode}`);
console.log(`头部:${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`主体:${chunk}`);
});
res.on('end', () => {
console.log('响应中没有更多数据。');
});
});
req.on('error', (e) => {
console.error(`请求出现问题:${e.message}`);
});
// 向请求主体写入数据
req.write(postData);
req.end();在示例中调用了 req.end()。使用 http.request() 时,必须始终调用 req.end() 来表示请求结束——即使没有数据写入请求主体。
如果在请求期间遇到任何错误(无论是 DNS 解析、TCP 级别错误还是实际的 HTTP 解析错误),都会在返回的请求对象上发出 'error' 事件。与所有 'error' 事件一样,如果没有注册监听器,错误将被抛出。
有几个特殊的头部需要注意。
-
发送 'Connection: keep-alive' 将通知 Node.js 与服务器的连接应持续到下一个请求。
-
发送 'Content-Length' 头部将禁用默认的分块编码。
-
发送 'Expect' 头部将立即发送请求头部。通常,发送 'Expect: 100-continue' 时,应设置超时和
'continue'事件的监听器。详见 RFC 2616 第 8.2.3 节。 -
发送 Authorization 头部将覆盖使用
auth选项来计算基本认证。
使用 URL 作为 options 的示例:
const options = new URL('http://abc:xyz@example.com');
const req = http.request(options, (res) => {
// ...
});在成功的请求中,将按以下顺序发出以下事件:
'socket''response''data'任意次数,在res对象上(如果响应主体为空,例如在大多数重定向中,则根本不会发出'data')'end'在res对象上
'close'
在连接错误的情况下,将发出以下事件:
'socket''error''close'
在响应接收之前连接过早关闭的情况下,将按以下顺序发出以下事件:
'socket''error'带有消息'Error: socket hang up'和代码'ECONNRESET'的错误'close'
在响应接收之后连接过早关闭的情况下,将按以下顺序发出以下事件:
'socket''response''data'任意次数,在res对象上
- (此处连接关闭)
'aborted'在res对象上'close''error'在res对象上,带有消息'Error: aborted'和代码'ECONNRESET'的错误'close'在res对象上
如果在分配套接字之前调用了 req.destroy(),将按以下顺序发出以下事件:
- (此处调用了
req.destroy()) 'error'带有消息'Error: socket hang up'和代码'ECONNRESET'的错误,或调用req.destroy()时使用的错误'close'
如果在连接成功之前调用了 req.destroy(),将按以下顺序发出以下事件:
'socket'- (此处调用了
req.destroy()) 'error'带有消息'Error: socket hang up'和代码'ECONNRESET'的错误,或调用req.destroy()时使用的错误'close'
如果在接收到响应之后调用了 req.destroy(),将按以下顺序发出以下事件:
'socket''response''data'任意次数,在res对象上
- (此处调用了
req.destroy()) 'aborted'在res对象上'close''error'在res对象上,带有消息'Error: aborted'和代码'ECONNRESET'的错误,或调用req.destroy()时使用的错误'close'在res对象上
如果在分配套接字之前调用了 req.abort(),将按以下顺序发出以下事件:
- (此处调用了
req.abort()) 'abort''close'
如果在连接成功之前调用了 req.abort(),将按以下顺序发出以下事件:
'socket'- (此处调用了
req.abort()) 'abort''error'带有消息'Error: socket hang up'和代码'ECONNRESET'的错误'close'
如果在接收到响应之后调用了 req.abort(),将按以下顺序发出以下事件:
'socket''response''data'任意次数,在res对象上
- (此处调用了
req.abort()) 'abort''aborted'在res对象上'error'在res对象上,带有消息'Error: aborted'和代码'ECONNRESET'的错误。'close''close'在res对象上
设置 timeout 选项或使用 setTimeout() 函数不会中止请求,除了添加 'timeout' 事件外不做任何事。
传递 AbortSignal 然后在相应的 AbortController 上调用 abort() 将与在请求上调用 .destroy() 的行为相同。具体来说,将发出 'error' 事件,错误消息为 'AbortError: The operation was aborted',代码为 'ABORT_ERR',以及 cause(如果提供了的话)。
对提供的 name 执行低级校验,这些校验与调用 res.setHeader(name, value) 时执行的校验相同。
将非法值作为 name 传入会导致抛出 TypeError,其特征为 code: 'ERR_INVALID_HTTP_TOKEN'。
在将标头传递给 HTTP 请求或响应之前,无需使用此方法。HTTP 模块会自动验证这些标头。
示例:
import { validateHeaderName } from 'node:http';
try {
validateHeaderName('');
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code); // --> 'ERR_INVALID_HTTP_TOKEN'
console.error(err.message); // --> 'Header name must be a valid HTTP token [""]'
}对提供的 value 执行低级验证,这些验证会在调用 res.setHeader(name, value) 时进行。
传递非法的 value 值将导致抛出 TypeError。
- Undefined 值错误标识为
code: 'ERR_HTTP_INVALID_HEADER_VALUE'。 - 无效值字符错误标识为
code: 'ERR_INVALID_CHAR'。
在将头信息传递给 HTTP 请求或响应之前,不必使用此方法。HTTP 模块将自动验证此类头信息。
示例:
import { validateHeaderValue } from 'node:http';
try {
validateHeaderValue('x-my-header', undefined);
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code === 'ERR_HTTP_INVALID_HEADER_VALUE'); // --> true
console.error(err.message); // --> '标头 "x-my-header" 的值 "undefined" 无效'
}
try {
validateHeaderValue('x-my-header', 'oʊmɪɡə');
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code === 'ERR_INVALID_CHAR'); // --> true
console.error(err.message); // --> '标头内容中的字符无效 ["x-my-header"]'
}<number>1000
。设置空闲 HTTP 解析器的最大数量。<Object>proxyEnv
option accepted by
Agent
.
Default:
process.env
.<Function>http.setGlobalProxyFromEnv()
was called.
Dynamically reset global configuration to enable built-in proxy support for fetch() and http.request()/https.request() at runtime, as an alternative to using the --use-env-proxy flag or the NODE_USE_ENV_PROXY environment variable. It can also be used to override settings configured from environment variables.
Because this function resets global configuration, any previously configured http.globalAgent, https.globalAgent, or undici global dispatcher will be overwritten after calling this function. It is recommended to call it before making any requests and to avoid calling it while any request is in progress.
For details on proxy URL formats and NO_PROXY syntax, see [Built-in Proxy Support][].
<WebSocket> 的浏览器兼容实现。
稳定性:1.1 - 积极开发中
当 Node.js 创建全局 agent 时,如果 NODE_USE_ENV_PROXY 环境变量设置为 1 或启用了 --use-env-proxy,全局 agent 将使用 proxyEnv: process.env 构建,从而启用基于环境变量的代理支持。
要动态且全局地启用代理支持,请使用 http.setGlobalProxyFromEnv()。
也可以通过在构建 agent 时传递 proxyEnv 选项来创建具有代理支持的自定义 agent。如果要只从环境变量继承配置,该值可以是 process.env,或者是具有特定设置以覆盖环境的对象。
检查 proxyEnv 的以下属性以配置代理支持。
HTTP_PROXY或http_proxy:HTTP 请求的代理服务器 URL。如果两者都设置,http_proxy优先。HTTPS_PROXY或https_proxy:HTTPS 请求的代理服务器 URL。如果两者都设置,https_proxy优先。NO_PROXY或no_proxy:绕过代理的主机逗号分隔列表。如果两者都设置,no_proxy优先。
如果请求是发往 Unix 域套接字的,代理设置将被忽略。
仅配置在该部署中可信且被授权的代理。代理可以观察连接元数据;对于普通 HTTP 请求,或者当 TLS 由代理终止或拦截时,它也可以观察请求和响应内容。Node.js 不支持将不可信代理视为隐私边界。部署运营者负责控制代理配置,并满足部署特定的网络策略和法律要求。
- HTTP 代理:
http://proxy.example.com:8080 - HTTPS 代理:
https://proxy.example.com:8080 - 带身份验证的代理:
http://username:password@proxy.example.com:8080
*- 绕过所有主机的代理example.com- 精确主机名匹配.example.com- 域名后缀匹配(匹配sub.example.com)*.example.com- 通配符域名匹配192.168.1.100- 精确 IP 地址匹配192.168.1.1-192.168.1.100- IP 地址范围example.com:8080- 带特定端口的主机名
多个条目应由逗号分隔。
NODE_USE_ENV_PROXY=1 HTTP_PROXY=http://proxy.example.com:8080 NO_PROXY=localhost,127.0.0.1 node client.js或使用 --use-env-proxy 标志。
HTTP_PROXY=http://proxy.example.com:8080 NO_PROXY=localhost,127.0.0.1 node --use-env-proxy client.js要使用 process.env(http.setGlobalProxyFromEnv() 的默认选项)动态且全局地启用代理支持:
const http = require('node:http');
// 从 process.env 读取与代理相关的环境变量
const restore = http.setGlobalProxyFromEnv();
// 后续请求将使用环境变量中配置的代理
http.get('http://www.example.com', (res) => {
// 如果设置了 HTTP_PROXY 或 http_proxy,此请求将通过代理
});
fetch('https://www.example.com', (res) => {
// 如果设置了 HTTPS_PROXY 或 https_proxy,此请求将通过代理
});
// 要恢复原始的全局 agent 和 dispatcher 设置,请调用返回的函数。
// restore();要使用自定义设置动态且全局地启用代理支持:
const http = require('node:http');
const restore = http.setGlobalProxyFromEnv({
http_proxy: 'http://proxy.example.com:8080',
https_proxy: 'https://proxy.example.com:8443',
no_proxy: 'localhost,127.0.0.1,.internal.example.com',
});
// 后续请求将使用配置的代理
http.get('http://www.example.com', (res) => {
// 此请求将通过 proxy.example.com:8080 进行代理
});
fetch('https://www.example.com', (res) => {
// 此请求将通过 proxy.example.com:8443 进行代理
});要创建具有内置代理支持的自定义 agent:
const http = require('node:http');
// 创建具有自定义代理支持的自定义 agent。
const agent = new http.Agent({ proxyEnv: { HTTP_PROXY: 'http://proxy.example.com:8080' } });
http.request({
hostname: 'www.example.com',
port: 80,
path: '/',
agent,
}, (res) => {
// 此请求将通过 proxy.example.com:8080 使用 HTTP 协议进行代理。
console.log(`STATUS: ${res.statusCode}`);
});或者,下面这些方法也同样有效:
const http = require('node:http');
// 使用小写选项名。
const agent1 = new http.Agent({ proxyEnv: { http_proxy: 'http://proxy.example.com:8080' } });
// 使用从环境变量继承的值,如果进程启动时带有
// HTTP_PROXY=http://proxy.example.com:8080 这将使用 process.env.HTTP_PROXY 中指定的代理服务器。
const agent2 = new http.Agent({ proxyEnv: process.env });