HTTP#

稳定性:2 - 稳定

源代码:lib/http.js

该模块同时包含客户端和服务器,可以通过 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', '*/*' ] 

类:http.Agent#

一个 Agent 负责管理 HTTP 客户端的连接持久性和重用。它为给定的主机和端口维护一个待处理请求队列,为每个请求重用单个套接字连接,直到队列为空,此时套接字要么被销毁,要么被放入一个池中,在那里它被保留以便再次用于对相同主机和端口的请求。它是被销毁还是被放入池中取决于 keepAlive 选项

池中的连接启用了 TCP Keep-Alive,但服务器仍然可能关闭空闲连接,在这种情况下,它们将从池中移除,当为该主机和端口发出新的 HTTP 请求时,将建立新的连接。服务器也可能拒绝在同一个连接上允许多个请求,在这种情况下,每次请求都必须重新建立连接,并且无法将其放入池中。Agent 仍然会向该服务器发出请求,但每个请求都将通过一个新的连接进行。

当连接被客户端或服务器关闭时,它会从池中移除。池中任何未使用的套接字都将被取消引用(unrefed),这样在没有未完成请求时,Node.js 进程就不会保持运行。(参见 socket.unref())。

在不再使用 Agent 实例时,调用 destroy() 是一个好习惯,因为未使用的套接字会消耗操作系统资源。

当套接字发出 'close' 事件或 'agentRemove' 事件时,套接字会从代理中移除。如果打算长时间保持一个 HTTP 请求打开而不将其保留在代理中,可以这样做:

http.get(options, (res) => {
  // Do stuff
}).on('socket', (socket) => {
  socket.emit('agentRemove');
}); 

一个代理也可以用于单个请求。通过向 http.get()http.request() 函数提供 {agent: false} 作为选项,将为客户端连接使用一个具有默认选项的一次性 Agent

agent:false:

http.get({
  hostname: 'localhost',
  port: 80,
  path: '/',
  agent: false,  // Create a new agent just for this one request
}, (res) => {
  // Do stuff with response
}); 

new Agent([options])#

  • options <Object> 用于在代理上设置的一组可配置选项。可以包含以下字段:
    • keepAlive <boolean> 即使没有未完成的请求,也保留套接字,这样它们可以用于未来的请求,而无需重新建立 TCP 连接。不要与 Connection 头的 keep-alive 值混淆。使用代理时,总是会发送 Connection: keep-alive 头,除非明确指定了 Connection 头,或者 keepAlivemaxSockets 选项分别设置为 falseInfinity,在这种情况下将使用 Connection: close默认值:false
    • keepAliveMsecs <number> 当使用 keepAlive 选项时,指定 TCP Keep-Alive 数据包的初始延迟。当 keepAlive 选项为 falseundefined 时忽略。默认值: 1000
    • agentKeepAliveTimeoutBuffer <number> 在确定套接字过期时间时,从服务器提供的 keep-alive: timeout=... 提示中减去的毫秒数。这个缓冲有助于确保代理在服务器关闭套接字之前稍微早一点关闭它,从而减少了在一个即将被服务器关闭的套接字上发送请求的机会。默认值:1000
    • maxSockets <number> 每个主机允许的最大套接字数量。如果同一个主机打开多个并发连接,每个请求都将使用新的套接字,直到达到 maxSockets 值。如果主机尝试打开超过 maxSockets 个连接,额外的请求将进入一个待处理请求队列,并在现有连接终止时进入活动连接状态。这确保在任何时间点,来自给定主机的活动连接最多为 maxSockets 个。默认值: Infinity
    • maxTotalSockets <number> 允许所有主机总共的最大套接字数量。每个请求都会使用一个新的套接字,直到达到最大值。默认值:Infinity
    • maxFreeSockets <number> 每个主机在空闲状态下保持打开的最大套接字数量。仅在 keepAlive 设置为 true 时相关。默认值:256
    • scheduling <string> 在选择下一个要使用的空闲套接字时应用的调度策略。可以是 'fifo''lifo'。两种调度策略的主要区别在于 'lifo' 选择最近使用的套接字,而 'fifo' 选择最久未使用的套接字。在每秒请求率较低的情况下,'lifo' 调度将降低选择可能因不活动而被服务器关闭的套接字的风险。在每秒请求率较高的情况下,'fifo' 调度将最大化打开套接字的数量,而 'lifo' 调度将使其尽可能低。默认值:'lifo'
    • timeout <number> 套接字超时时间,单位为毫秒。这将在套接字创建时设置超时。
    • proxyEnv <Object> | <undefined> 用于代理配置的环境变量。详情请见内置代理支持默认值:undefined
      • HTTP_PROXY <string> | <undefined> HTTP 请求应使用的代理服务器 URL。如果未定义,HTTP 请求不使用代理。
      • HTTPS_PROXY <string> | <undefined> HTTPS 请求应使用的代理服务器 URL。如果未定义,HTTPS 请求不使用代理。
      • NO_PROXY <string> | <undefined> 指定不应通过代理路由的端点的模式。
      • http_proxy <string> | <undefined>HTTP_PROXY 相同。如果两者都设置了,http_proxy 优先。
      • https_proxy <string> | <undefined>HTTPS_PROXY 相同。如果两者都设置了,https_proxy 优先。
      • no_proxy <string> | <undefined>NO_PROXY 相同。如果两者都设置了,no_proxy 优先。
    • defaultPort <number> 当请求中未指定端口时使用的默认端口。默认值:80
    • protocol <string> 用于代理的协议。默认值:'http:'

也支持 socket.connect() 中的 options

要配置其中任何一个,必须创建一个自定义的 http.Agent 实例。

import { Agent, request } from 'node:http';
const keepAliveAgent = new Agent({ keepAlive: true });
options.agent = keepAliveAgent;
request(options, onResponseCallback);const http = require('node:http');
const keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
http.request(options, onResponseCallback);

agent.createConnection(options[, callback])#

生成一个用于 HTTP 请求的套接字/流。

默认情况下,此函数与 net.createConnection() 相同。但是,如果需要更大的灵活性,自定义代理可以覆盖此方法。

套接字/流可以通过两种方式提供:通过从此函数返回套接字/流,或者将套接字/流传递给 callback

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此方法保证返回一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

callback 的签名为 (err, stream)

agent.keepSocketAlive(socket)#

socket 从请求中分离并且可以被 Agent 持久化时调用。默认行为是:

socket.setKeepAlive(true, this.keepAliveMsecs);
socket.unref();
return true; 

此方法可以被特定的 Agent 子类覆盖。如果此方法返回一个假值,套接字将被销毁,而不是为下一次请求持久化。

socket 参数可以是 <net.Socket> 的实例,它是 <stream.Duplex> 的子类。

agent.reuseSocket(socket, request)#

socket 因为 keep-alive 选项被持久化后附加到 request 时调用。默认行为是:

socket.ref(); 

此方法可以被特定的 Agent 子类覆盖。

socket 参数可以是 <net.Socket> 的实例,它是 <stream.Duplex> 的子类。

agent.destroy()#

销毁当前被代理使用的所有套接字。

通常不需要这样做。但是,如果使用启用了 keepAlive 的代理,最好在不再需要时明确关闭代理。否则,套接字可能会保持打开很长时间,直到服务器终止它们。

agent.freeSockets#

一个对象,其中包含当 keepAlive 启用时,当前等待代理使用的套接字数组。请勿修改。

freeSockets 列表中的套接字将在 'timeout' 事件发生时被自动销毁并从数组中移除。

agent.getName([options])#

  • options <Object> 一组为名称生成提供信息的选项。
    • host <string> 发出请求的服务器的域名或 IP 地址。
    • port <number> 远程服务器的端口。
    • localAddress <string> 发出请求时用于网络连接绑定的本地接口。
    • family <integer> 如果不为 undefined,则必须是 4 或 6。
  • 返回: <string>

为一组请求选项获取一个唯一的名称,以确定连接是否可以被重用。对于 HTTP 代理,它返回 host:port:localAddresshost:port:localAddress:family。对于 HTTPS 代理,名称包括 CA、证书、密码套件以及其他决定套接字可重用性的 HTTPS/TLS 特定选项。

agent.maxFreeSockets#

默认设置为 256。对于启用了 keepAlive 的代理,这设置了在空闲状态下保持打开的最大套接字数量。

agent.maxSockets#

默认设置为 Infinity。确定代理可以为每个源打开多少个并发套接字。源是 agent.getName() 的返回值。

agent.maxTotalSockets#

默认设置为 Infinity。确定代理可以打开多少个并发套接字。与 maxSockets 不同,此参数适用于所有源。

agent.requests#

一个对象,其中包含尚未分配给套接字的请求队列。请勿修改。

agent.sockets#

一个对象,其中包含代理当前正在使用的套接字数组。请勿修改。

类:http.ClientRequest#

此对象在内部创建并从 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 设置为 trueContent-Length 头部值不匹配将导致抛出一个 Error,其 code'ERR_HTTP_CONTENT_LENGTH_MISMATCH'

Content-Length 值应以字节为单位,而不是字符。使用 Buffer.byteLength() 来确定主体的字节长度。

事件:'abort'#

稳定性:0 - 已弃用。请改用监听 'close' 事件。

当请求被客户端中止时发出。此事件仅在第一次调用 abort() 时发出。

事件:'close'#

表示请求已完成,或者其底层连接在响应完成前被过早终止。

事件:'connect'#

每当服务器以 CONNECT 方法响应请求时发出。如果未监听此事件,接收到 CONNECT 方法的客户端的连接将被关闭。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

一个演示如何监听 'connect' 事件的客户端和服务器对:

import { createServer, request } from 'node:http';
import { connect } from 'node:net';
import { URL } from 'node:url';

// Create an HTTP tunneling proxy
const proxy = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
  // Connect to an origin server
  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);
  });
});

// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

  // Make a request to a tunneling proxy
  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('got connected!');

    // Make a request over an HTTP tunnel
    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();
    });
  });
});const http = require('node:http');
const net = require('node:net');
const { URL } = require('node:url');

// Create an HTTP tunneling proxy
const proxy = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
  // Connect to an origin server
  const { port, hostname } = new URL(`http://${req.url}`);
  const serverSocket = net.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);
  });
});

// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

  // Make a request to a tunneling proxy
  const options = {
    port: 1337,
    host: '127.0.0.1',
    method: 'CONNECT',
    path: 'www.google.com:80',
  };

  const req = http.request(options);
  req.end();

  req.on('connect', (res, socket, head) => {
    console.log('got connected!');

    // Make a request over an HTTP tunnel
    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();
    });
  });
});

事件:'continue'#

当服务器发送“100 Continue”HTTP 响应时发出,通常是因为请求包含了“Expect: 100-continue”。这是一个指示客户端应该发送请求体的指令。

事件:'finish'#

当请求已发送时发出。更具体地说,此事件在响应头和主体的最后一部分被交给操作系统以通过网络传输时发出。它并不意味着服务器已经收到了任何东西。

事件:'information'#

当服务器发送 1xx 中间响应(不包括 101 Upgrade)时发出。此事件的监听器将收到一个包含 HTTP 版本、状态码、状态消息、键值头对象以及包含原始头名称及其对应值的数组的对象。

import { request } from 'node:http';

const options = {
  host: '127.0.0.1',
  port: 8080,
  path: '/length_request',
};

// Make a request
const req = request(options);
req.end();

req.on('information', (info) => {
  console.log(`Got information prior to main response: ${info.statusCode}`);
});const http = require('node:http');

const options = {
  host: '127.0.0.1',
  port: 8080,
  path: '/length_request',
};

// Make a request
const req = http.request(options);
req.end();

req.on('information', (info) => {
  console.log(`Got information prior to main response: ${info.statusCode}`);
});

101 Upgrade 状态不会触发此事件,因为它们脱离了传统的 HTTP 请求/响应链,例如 WebSocket、就地 TLS 升级或 HTTP 2.0。要接收 101 Upgrade 的通知,请改为监听 'upgrade' 事件。

事件:'response'#

当收到对此请求的响应时发出。此事件仅发出一次。

事件:'socket'#

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

事件:'timeout'#

当底层套接字因不活动而超时时发出。这只通知套接字已处于空闲状态。必须手动销毁请求。

另请参阅:request.setTimeout()

事件:'upgrade'#

每当服务器以升级响应请求时发出。如果未监听此事件且响应状态码为 101 Switching Protocols,则接收到升级头的客户端连接将被关闭。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

一个演示如何监听 'upgrade' 事件的客户端-服务器对。

import http from 'node:http';
import process from 'node:process';

// Create an HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
server.on('upgrade', (req, socket, head) => {
  socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
               'Upgrade: WebSocket\r\n' +
               'Connection: Upgrade\r\n' +
               '\r\n');

  socket.pipe(socket); // echo back
});

// Now that server is running
server.listen(1337, '127.0.0.1', () => {

  // make a request
  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, socket, upgradeHead) => {
    console.log('got upgraded!');
    socket.end();
    process.exit(0);
  });
});const http = require('node:http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
server.on('upgrade', (req, socket, head) => {
  socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
               'Upgrade: WebSocket\r\n' +
               'Connection: Upgrade\r\n' +
               '\r\n');

  socket.pipe(socket); // echo back
});

// Now that server is running
server.listen(1337, '127.0.0.1', () => {

  // make a request
  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, socket, upgradeHead) => {
    console.log('got upgraded!');
    socket.end();
    process.exit(0);
  });
});

request.abort()#

稳定性:0 - 已弃用:请改用 request.destroy()

将请求标记为正在中止。调用此方法将导致响应中剩余的数据被丢弃,并且套接字将被销毁。

request.aborted#

稳定性:0 - 已弃用。请改用检查 request.destroyed

如果请求已被中止,request.aborted 属性将为 true

request.connection#

稳定性:0 - 已弃用。请使用 request.socket

参见 request.socket

request.cork()#

参见 writable.cork()

request.end([data[, encoding]][, callback])#

完成发送请求。如果请求体的任何部分未发送,它将把它们刷新到流中。如果请求是分块的,这将发送终止符 '0\r\n\r\n'

如果指定了 data,则等同于调用 request.write(data, encoding) 后再调用 request.end(callback)

如果指定了 callback,它将在请求流完成时被调用。

request.destroy([error])#

  • error <Error> 可选,一个随 'error' 事件发出的错误。
  • 返回:<this>

销毁请求。可选地发出一个 'error' 事件,并发出一个 'close' 事件。调用此方法将导致响应中剩余的数据被丢弃,并且套接字将被销毁。

更多细节请参见 writable.destroy()

request.destroyed#

request.destroy() 被调用后为 true

更多细节请参见 writable.destroyed

request.finished#

稳定性:0 - 已弃用。请使用 request.writableEnded

如果 request.end() 已被调用,则 request.finished 属性为 true。如果请求是通过 http.get() 发起的,request.end() 将被自动调用。

request.flushHeaders()#

刷新请求头。

出于效率考虑,Node.js 通常会缓冲请求头,直到调用 request.end() 或写入第一个请求数据块。然后它会尝试将请求头和数据打包成一个 TCP 数据包。

这通常是期望的行为(它节省了一次 TCP 往返),但当第一个数据可能要晚得多才发送时,情况就不同了。request.flushHeaders() 绕过了这种优化,并启动请求。

request.getHeader(name)#

读取请求中的一个头。名称不区分大小写。返回值的类型取决于提供给 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' is 'text/html'
const contentLength = request.getHeader('Content-Length');
// 'contentLength' is of type number
const cookie = request.getHeader('Cookie');
// 'cookie' is of type string[] 

request.getHeaderNames()#

返回一个包含当前传出头唯一名称的数组。所有头名称均为小写。

request.setHeader('Foo', 'bar');
request.setHeader('Cookie', ['foo=bar', 'bar=baz']);

const headerNames = request.getHeaderNames();
// headerNames === ['foo', 'cookie'] 

request.getHeaders()#

返回当前传出头的浅拷贝。由于使用的是浅拷贝,数组值可以在不额外调用各种与头相关的 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.getRawHeaderNames()#

返回一个包含当前传出的原始头唯一名称的数组。头名称以其确切的大小写形式返回。

request.setHeader('Foo', 'bar');
request.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headerNames = request.getRawHeaderNames();
// headerNames === ['Foo', 'Set-Cookie'] 

request.hasHeader(name)#

如果由 name 标识的头当前设置在传出头中,则返回 true。头名称匹配不区分大小写。

const hasContentType = request.hasHeader('content-type'); 

request.maxHeadersCount#

限制最大响应头数量。如果设置为 0,则不应用任何限制。

request.path#

request.method#

request.host#

request.protocol#

request.removeHeader(name)#

移除已在头对象中定义的头。

request.removeHeader('Content-Type'); 

request.reusedSocket#

  • 类型:<boolean> 请求是否通过重用的套接字发送。

当通过启用 keep-alive 的代理发送请求时,底层套接字可能会被重用。但如果服务器在不巧的时间关闭了连接,客户端可能会遇到 'ECONNRESET' 错误。

import http from 'node:http';

// Server has a 5 seconds keep-alive timeout by default
http
  .createServer((req, res) => {
    res.write('hello\n');
    res.end();
  })
  .listen(3000);

setInterval(() => {
  // Adapting a keep-alive agent
  http.get('https://:3000', { agent }, (res) => {
    res.on('data', (data) => {
      // Do nothing
    });
  });
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeoutconst http = require('node:http');

// Server has a 5 seconds keep-alive timeout by default
http
  .createServer((req, res) => {
    res.write('hello\n');
    res.end();
  })
  .listen(3000);

setInterval(() => {
  // Adapting a keep-alive agent
  http.get('https://:3000', { agent }, (res) => {
    res.on('data', (data) => {
      // Do nothing
    });
  });
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeout

通过标记一个请求是否重用了套接字,我们可以基于此进行自动错误重试。

import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });

function retriableRequest() {
  const req = http
    .get('https://:3000', { agent }, (res) => {
      // ...
    })
    .on('error', (err) => {
      // Check if retry is needed
      if (req.reusedSocket && err.code === 'ECONNRESET') {
        retriableRequest();
      }
    });
}

retriableRequest();const http = require('node:http');
const agent = new http.Agent({ keepAlive: true });

function retriableRequest() {
  const req = http
    .get('https://:3000', { agent }, (res) => {
      // ...
    })
    .on('error', (err) => {
      // Check if retry is needed
      if (req.reusedSocket && err.code === 'ECONNRESET') {
        retriableRequest();
      }
    });
}

retriableRequest();

request.setHeader(name, value)#

为头对象设置单个头值。如果此头已存在于待发送的头中,其值将被替换。在此处使用字符串数组可以发送多个同名的头。非字符串值将不加修改地存储。因此,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)}`); 

request.setNoDelay([noDelay])#

一旦为此请求分配了套接字并连接,将调用 socket.setNoDelay()

request.setSocketKeepAlive([enable][, initialDelay])#

一旦为此请求分配了套接字并连接,将调用 socket.setKeepAlive()

request.setTimeout(timeout[, callback])#

一旦为此请求分配了套接字并连接,将调用 socket.setTimeout()

request.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(`Your IP address is ${ip} and your source port is ${port}.`);
  // Consume response object
});const http = require('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(`Your IP address is ${ip} and your source port is ${port}.`);
  // Consume response object
});

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此属性保证是 <net.Socket> 类(<stream.Duplex> 的子类)的实例。

request.uncork()#

参见 writable.uncork()

request.writableEnded#

在调用 request.end() 之后为 true。此属性不表示数据是否已刷新,请改用 request.writableFinished

request.writableFinished#

如果在发出 'finish' 事件之前,所有数据都已刷新到底层系统,则为 true

request.write(chunk[, encoding][, callback])#

发送一部分主体。此方法可以多次调用。如果未设置 Content-Length,数据将自动以 HTTP 分块传输编码进行编码,以便服务器知道数据何时结束。将添加 Transfer-Encoding: chunked 头。必须调用 request.end() 来完成发送请求。

encoding 参数是可选的,仅当 chunk 是字符串时适用。默认为 'utf8'

callback 参数是可选的,当此数据块被刷新时将被调用,但仅当该数据块非空时。

如果所有数据都成功刷新到内核缓冲区,则返回 true。如果全部或部分数据被排队在用户内存中,则返回 false。当缓冲区再次空闲时,将发出 'drain' 事件。

当使用空字符串或空缓冲区调用 write 函数时,它什么也不做,并等待更多输入。

类:http.Server#

事件:'checkContinue'#

每当收到带有 HTTP Expect: 100-continue 的请求时发出。如果未监听此事件,服务器将自动酌情响应 100 Continue

处理此事件涉及调用 response.writeContinue()(如果客户端应继续发送请求体),或生成适当的 HTTP 响应(例如 400 Bad Request)(如果客户端不应继续发送请求体)。

当此事件被发出并处理时,'request' 事件将不会被发出。

事件:'checkExpectation'#

每当收到带有 HTTP Expect 头且其值不是 100-continue 的请求时发出。如果未监听此事件,服务器将自动酌情响应 417 Expectation Failed

当此事件被发出并处理时,'request' 事件将不会被发出。

事件:'clientError'#

如果客户端连接发出 'error' 事件,它将被转发到这里。此事件的监听器负责关闭/销毁底层套接字。例如,可能希望用自定义的 HTTP 响应来更优雅地关闭套接字,而不是突然切断连接。套接字**必须在监听器结束前关闭或销毁**。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

默认行为是尝试使用 HTTP '400 Bad Request' 关闭套接字,或者在发生 HPE_HEADER_OVERFLOW 错误的情况下使用 HTTP '431 Request Header Fields Too Large'。如果套接字不可写或当前附加的 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);const http = require('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' 事件发生时,没有 requestresponse 对象,因此任何发送的 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');
}); 

事件:'close'#

当服务器关闭时发出。

事件:'connect'#

每当客户端请求 HTTP CONNECT 方法时发出。如果未监听此事件,则请求 CONNECT 方法的客户端的连接将被关闭。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

此事件发出后,请求的套接字将不会有 'data' 事件监听器,这意味着需要绑定它来处理发送到该套接字上的服务器的数据。

事件:'connection'#

当建立新的 TCP 流时,会发出此事件。socket 通常是 net.Socket 类型的对象。通常用户不希望访问此事件。特别是,由于协议解析器如何附加到套接字,套接字不会发出 'readable' 事件。也可以通过 request.socket 访问 socket

此事件也可以由用户显式发出,以将连接注入 HTTP 服务器。在这种情况下,可以传递任何 Duplex 流。

如果在此处调用 socket.setTimeout(),当套接字处理完一个请求后,超时将被替换为 server.keepAliveTimeout(如果 server.keepAliveTimeout 非零)。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

事件:'dropRequest'#

当套接字上的请求数达到 server.maxRequestsPerSocket 的阈值时,服务器将丢弃新请求并发出 'dropRequest' 事件,然后向客户端发送 503

事件:'request'#

每次有请求时发出。每个连接可能有多个请求(在 HTTP Keep-Alive 连接的情况下)。

事件:'upgrade'#

每当客户端的 HTTP 升级请求被接受时发出。默认情况下,所有 HTTP 升级请求都会被忽略(即只发出常规的 'request' 事件,遵循正常的 HTTP 请求/响应流程),除非您监听此事件,在这种情况下,它们都会被接受(即会发出 'upgrade' 事件,未来的通信必须直接通过原始套接字处理)。您可以通过使用服务器的 shouldUpgradeCallback 选项来更精确地控制这一点。

监听此事件是可选的,客户端不能坚持协议更改。

此事件发出后,请求的套接字将不会有 'data' 事件监听器,这意味着需要绑定它来处理发送到该套接字上的服务器的数据。

如果升级被 shouldUpgradeCallback 接受,但没有注册事件处理程序,则套接字将被销毁,导致客户端连接立即关闭。

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此事件保证传递一个 <net.Socket> 类的实例,该类是 <stream.Duplex> 的子类。

server.close([callback])#

停止服务器接受新连接,并关闭所有连接到此服务器且未发送请求或等待响应的连接。参见 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);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
}, 10000); 

server.closeAllConnections()#

关闭连接到此服务器的所有已建立的 HTTP(S) 连接,包括正在发送请求或等待响应的活动连接。这*不会*销毁已升级到不同协议(如 WebSocket 或 HTTP/2)的套接字。

这是一种强制关闭所有连接的方法,应谨慎使用。当与 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);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
  // Closes all connections, ensuring the server closes successfully
  server.closeAllConnections();
}, 10000); 

server.closeIdleConnections()#

关闭连接到此服务器且未发送请求或等待响应的所有连接。

从 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);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
  // Closes idle connections, such as keep-alive connections. Server will close
  // once remaining active connections are terminated
  server.closeIdleConnections();
}, 10000); 

server.headersTimeout#

限制解析器等待接收完整 HTTP 头的时长。

如果超时到期,服务器会响应状态码 408,而不会将请求转发给请求监听器,然后关闭连接。

必须将其设置为非零值(例如 120 秒)以防止潜在的拒绝服务攻击,以防服务器在没有反向代理的情况下部署。

server.listen()#

启动 HTTP 服务器监听连接。此方法与 net.Server 中的 server.listen() 相同。

server.listening#

  • 类型:<boolean> 表示服务器是否正在监听连接。

server.maxHeadersCount#

限制最大传入头数量。如果设置为 0,则不应用任何限制。

server.requestTimeout#

设置从客户端接收整个请求的超时值(以毫秒为单位)。

如果超时到期,服务器会响应状态码 408,而不会将请求转发给请求监听器,然后关闭连接。

必须将其设置为非零值(例如 120 秒)以防止潜在的拒绝服务攻击,以防服务器在没有反向代理的情况下部署。

server.setTimeout([msecs][, callback])#

设置套接字的超时值,并在发生超时时在服务器对象上发出 'timeout' 事件,并将套接字作为参数传递。

如果服务器对象上有 'timeout' 事件监听器,则它将以超时的套接字作为参数被调用。

默认情况下,服务器不会使套接字超时。但是,如果为服务器的 'timeout' 事件分配了回调函数,则必须显式处理超时。

server.maxRequestsPerSocket#

  • 类型:<number> 每个套接字的请求数。默认值: 0 (无限制)

套接字在关闭 keep-alive 连接之前可以处理的最大请求数。

值为 0 将禁用该限制。

当达到限制时,它会将 Connection 头部的值设置为 close,但实际上不会关闭连接,达到限制后发送的后续请求将得到 503 Service Unavailable 的响应。

server.timeout#

  • 类型:<number> 超时时间(毫秒)。默认值: 0(无超时)

在套接字被认为超时之前的不活动毫秒数。

值为 0 将禁用对传入连接的超时行为。

套接字超时逻辑是在连接时设置的,因此更改此值仅影响到服务器的新连接,而不影响任何现有连接。

server.keepAliveTimeout#

  • 类型:<number> 超时时间(毫秒)。默认值: 5000 (5 秒)。

服务器在完成写入最后一个响应后,需要等待额外传入数据的不活动毫秒数,超过此时间套接字将被销毁。

此超时值与 server.keepAliveTimeoutBuffer 选项结合使用以确定实际的套接字超时,计算方式为:socketTimeout = keepAliveTimeout + keepAliveTimeoutBuffer 如果服务器在 keep-alive 超时触发之前收到新数据,它将重置常规的不活动超时,即 server.timeout

值为 0 将禁用传入连接的 keep-alive 超时行为。值为 0 使 HTTP 服务器的行为类似于 8.0.0 之前的 Node.js 版本,这些版本没有 keep-alive 超时。

套接字超时逻辑是在连接时设置的,因此更改此值仅影响到服务器的新连接,而不影响任何现有连接。

server.keepAliveTimeoutBuffer#

  • 类型:<number> 超时时间(毫秒)。默认值: 1000 (1 秒)。

一个额外的缓冲时间,添加到 server.keepAliveTimeout 以延长内部套接字超时。

此缓冲通过将套接字超时略微延长到宣告的 keep-alive 超时之后,帮助减少连接重置 (ECONNRESET) 错误。

此选项仅适用于新的传入连接。

server[Symbol.asyncDispose]()#

调用 server.close() 并返回一个 Promise,该 Promise 在服务器关闭时兑现。

类:http.ServerResponse#

此对象由 HTTP 服务器内部创建,而非由用户创建。它作为第二个参数传递给 'request' 事件。

事件:'close'#

表示响应已完成,或者其底层连接在响应完成前被过早终止。

事件:'finish'#

当响应已发送时发出。更具体地说,当响应头和主体的最后一部分已移交给操作系统以通过网络传输时,会发出此事件。这并不意味着客户端已经收到了任何东西。

response.addTrailers(headers)#

此方法向响应添加 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.connection#

稳定性:0 - 已弃用。请使用 response.socket

参见 response.socket

response.cork()#

参见 writable.cork()

response.end([data[, encoding]][, callback])#

此方法向服务器发出信号,表示所有响应头和主体都已发送;服务器应认为此消息已完成。必须在每个响应上调用 response.end() 方法。

如果指定了 data,其效果类似于调用 response.write(data, encoding) 后再调用 response.end(callback)

如果指定了 callback,它将在响应流完成时被调用。

response.finished#

稳定性:0 - 已弃用。请使用 response.writableEnded

如果 response.end() 已被调用,则 response.finished 属性将为 true

response.flushHeaders()#

刷新响应头。另请参阅:request.flushHeaders()

response.getHeader(name)#

读出一个已经排队但尚未发送给客户端的标头。名称不区分大小写。返回值的类型取决于提供给 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 is 'text/html'
const contentLength = response.getHeader('Content-Length');
// contentLength is of type number
const setCookie = response.getHeader('set-cookie');
// setCookie is of type string[] 

response.getHeaderNames()#

返回一个包含当前传出头唯一名称的数组。所有头名称均为小写。

response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headerNames = response.getHeaderNames();
// headerNames === ['foo', 'set-cookie'] 

response.getHeaders()#

返回当前传出头的浅拷贝。由于使用的是浅拷贝,数组值可以在不额外调用各种与头相关的 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)#

如果由 name 标识的头当前设置在传出头中,则返回 true。头名称匹配不区分大小写。

const hasContentType = response.hasHeader('content-type'); 

response.headersSent#

布尔值(只读)。如果标头已发送,则为 true,否则为 false。

response.removeHeader(name)#

移除一个已排队等待隐式发送的标头。

response.removeHeader('Content-Encoding'); 

response.req#

对原始 HTTP request 对象的引用。

response.sendDate#

当为 true 时,如果 Date 标头尚未存在于标头中,则将自动生成并发送到响应中。默认为 true。

这只应在测试时禁用;HTTP 要求响应中包含 Date 标头。

response.setHeader(name, value)#

返回响应对象。

为隐式标头设置单个标头值。如果此标头已存在于待发送的标头中,其值将被替换。在此处使用字符串数组可发送多个同名标头。非字符串值将不加修改地存储。因此,response.getHeader() 可能返回非字符串值。但是,非字符串值在网络传输时将被转换为字符串。相同的响应对象将返回给调用者,以实现链式调用。

response.setHeader('Content-Type', 'text/html'); 

response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']); 

尝试设置包含无效字符的标头字段名称或值将导致抛出 TypeError

当使用 response.setHeader() 设置标头时,它们将与传递给 response.writeHead() 的任何标头合并,其中传递给 response.writeHead() 的标头具有优先权。

// 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');
}); 

如果调用了 response.writeHead() 方法且此方法尚未被调用,它将直接将提供的标头值写入网络通道,而不在内部缓存,并且对该标头调用 response.getHeader() 将不会产生预期的结果。如果希望逐步填充标头并可能在将来进行检索和修改,请使用 response.setHeader() 而不是 response.writeHead()

response.setTimeout(msecs[, callback])#

将 Socket 的超时值设置为 msecs。如果提供了回调函数,则将其作为响应对象上 'timeout' 事件的监听器添加。

如果没有向请求、响应或服务器添加 'timeout' 监听器,则套接字在超时时会被销毁。如果为请求、响应或服务器的 'timeout' 事件分配了处理程序,则必须显式处理超时的套接字。

response.socket#

对底层套接字的引用。通常用户不会希望访问此属性。特别是,由于协议解析器如何附加到套接字,套接字不会发出 'readable' 事件。在 response.end() 之后,该属性被置为 null。

import http from 'node:http';
const server = http.createServer((req, res) => {
  const ip = res.socket.remoteAddress;
  const port = res.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);const http = require('node:http');
const server = http.createServer((req, res) => {
  const ip = res.socket.remoteAddress;
  const port = res.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);

除非用户指定了除 <net.Socket> 之外的套接字类型,否则此属性保证是 <net.Socket> 类(<stream.Duplex> 的子类)的实例。

response.statusCode#

使用隐式标头时(不显式调用 response.writeHead()),此属性控制在标头刷新时将发送给客户端的状态码。

response.statusCode = 404; 

响应头发送给客户端后,此属性指示已发送的状态码。

response.statusMessage#

使用隐式标头时(不显式调用 response.writeHead()),此属性控制在标头刷新时将发送给客户端的状态消息。如果此项保留为 undefined,则将使用该状态码的标准消息。

response.statusMessage = 'Not found'; 

响应头发送给客户端后,此属性指示已发送的状态消息。

response.strictContentLength#

如果设置为 true,Node.js 将检查 Content-Length 标头值和主体大小(以字节为单位)是否相等。不匹配的 Content-Length 标头值将导致抛出一个 Error,其标识为 code: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH'

response.uncork()#

参见 writable.uncork()

response.writableEnded#

response.end() 调用后为 true。此属性不表示数据是否已被刷新,为此请改用 response.writableFinished

response.writableFinished#

如果在发出 'finish' 事件之前,所有数据都已刷新到底层系统,则为 true

response.write(chunk[, encoding][, callback])#

如果调用此方法且未调用 response.writeHead(),它将切换到隐式标头模式并刷新隐式标头。

这会发送一块响应主体。此方法可以多次调用以提供主体的后续部分。

如果在 createServer 中将 rejectNonStandardBodyWrites 设置为 true,则当请求方法或响应状态不支持内容时,不允许写入主体。如果尝试为 HEAD 请求或作为 204304 响应的一部分写入主体,则会抛出一个同步的 Error,其代码为 ERR_HTTP_BODY_NOT_ALLOWED

chunk 可以是字符串或缓冲区。如果 chunk 是字符串,则第二个参数指定如何将其编码为字节流。当此数据块被刷新时,将调用 callback

这是原始的 HTTP 主体,与可能使用的高级多部分主体编码无关。

第一次调用 response.write() 时,它会向客户端发送缓冲的标头信息和主体的第一块。第二次调用 response.write() 时,Node.js 假定数据将被流式传输,并单独发送新数据。也就是说,响应被缓冲到主体的第一块为止。

如果所有数据都成功刷新到内核缓冲区,则返回 true。如果全部或部分数据被排队在用户内存中,则返回 false。当缓冲区再次空闲时,将发出 'drain' 事件。

response.writeContinue()#

向客户端发送 HTTP/1.1 100 Continue 消息,表示应发送请求主体。请参阅 Server 上的 'checkContinue' 事件。

response.writeEarlyHints(hints[, callback])#

向客户端发送一个 HTTP/1.1 103 Early Hints 消息,并带有一个 Link 标头,指示用户代理可以预加载/预连接链接的资源。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 for diagnostics',
});

const earlyHintsCallback = () => console.log('early hints message sent');
response.writeEarlyHints({
  'link': earlyHintsLinks,
}, earlyHintsCallback); 

response.writeHead(statusCode[, statusMessage][, headers])#

向请求发送响应标头。状态码是一个 3 位的 HTTP 状态码,例如 404。最后一个参数 headers 是响应标头。可以选择性地将人类可读的 statusMessage 作为第二个参数。

headers 可以是一个数组,其中键和值在同一个列表中。它*不是*一个元组列表。因此,偶数偏移量是键值,奇数偏移量是相关联的值。数组的格式与 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()

// 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');
}); 

Content-Length 是以字节而不是字符为单位读取的。使用 Buffer.byteLength() 来确定主体的字节长度。Node.js 将检查 Content-Length 和已传输的主体长度是否相等。

尝试设置包含无效字符的标头字段名称或值将导致抛出 TypeError

response.writeProcessing()#

向客户端发送一个 HTTP/1.1 102 Processing 消息,表示应发送请求主体。

类:http.IncomingMessage#

IncomingMessage 对象由 http.Serverhttp.ClientRequest 创建,并分别作为 'request''response' 事件的第一个参数传递。它可用于访问响应状态、标头和数据。

不同于其 socket 值(<stream.Duplex> 的子类),IncomingMessage 本身扩展了 <stream.Readable>,并且是单独创建的,用于解析和发出传入的 HTTP 标头和有效负载,因为在保持连接的情况下,底层套接字可能会被多次重用。

事件:'aborted'#

稳定性:0 - 已弃用。请监听 'close' 事件。

当请求被中止时发出。

事件:'close'#

当请求完成时发出。

message.aborted#

稳定性:0 - 已弃用。请检查 <stream.Readable> 中的 message.destroyed

如果请求已被中止,message.aborted 属性将为 true

message.complete#

如果已接收并成功解析了完整的 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(
        'The connection was terminated while the message was still being sent');
  });
}); 

message.connection#

稳定性:0 - 已弃用。请使用 message.socket

message.socket 的别名。

message.destroy([error])#

在接收到 IncomingMessage 的套接字上调用 destroy()。如果提供了 error,则在套接字上发出 'error' 事件,并将 error 作为参数传递给该事件的任何监听器。

message.headers#

请求/响应标头对象。

标头名称和值的键值对。标头名称是小写的。

// Prints something like:
//
// { 'user-agent': 'curl/7.22.0',
//   host: '127.0.0.1:8000',
//   accept: '*/*' }
console.log(request.headers); 

原始标头中的重复项根据标头名称按以下方式处理:

  • ageauthorizationcontent-lengthcontent-typeetagexpiresfromhostif-modified-sinceif-unmodified-sincelast-modifiedlocationmax-forwardsproxy-authorizationrefererretry-afterserveruser-agent 的重复项将被丢弃。要允许将上面列出的标头的重复值合并,请在 http.request()http.createServer() 中使用 joinDuplicateHeaders 选项。更多信息请参阅 RFC 9110 第 5.3 节。
  • set-cookie 始终是一个数组。重复项会被添加到数组中。
  • 对于重复的 cookie 标头,值会用 ; 连接在一起。
  • 对于所有其他标头,值会用 , 连接在一起。

message.headersDistinct#

类似于 message.headers,但没有连接逻辑,并且值始终是字符串数组,即使对于只接收一次的标头也是如此。

// Prints something like:
//
// { 'user-agent': ['curl/7.22.0'],
//   host: ['127.0.0.1:8000'],
//   accept: ['*/*'] }
console.log(request.headersDistinct); 

message.httpVersion#

对于服务器请求,是客户端发送的 HTTP 版本。对于客户端响应,是所连接服务器的 HTTP 版本。可能是 '1.1''1.0'

此外,message.httpVersionMajor 是第一个整数,message.httpVersionMinor 是第二个。

message.method#

仅对从 http.Server 获取的请求有效。

请求方法为字符串。只读。例如:'GET''DELETE'

message.rawHeaders#

原始请求/响应标头列表,与接收时完全一致。

键和值在同一个列表中。它*不是*一个元组列表。因此,偶数偏移量是键值,奇数偏移量是相关联的值。

标头名称不会小写,重复项也不会合并。

// Prints something like:
//
// [ '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); 

message.rawTrailers#

原始请求/响应尾部键和值,与接收时完全一致。仅在 'end' 事件时填充。

message.setTimeout(msecs[, callback])#

调用 message.socket.setTimeout(msecs, callback)

message.socket#

与连接关联的 net.Socket 对象。

在 HTTPS 支持下,使用 request.socket.getPeerCertificate() 获取客户端的身份验证详细信息。

此属性保证是 <net.Socket> 类的实例,它是 <stream.Duplex> 的子类,除非用户指定了 <net.Socket> 以外的套接字类型或内部置为 null。

message.statusCode#

仅对从 http.ClientRequest 获取的响应有效。

3 位数的 HTTP 响应状态码。例如 404

message.statusMessage#

仅对从 http.ClientRequest 获取的响应有效。

HTTP 响应状态消息(原因短语)。例如 OKInternal Server Error

message.trailers#

请求/响应尾部对象。仅在 'end' 事件时填充。

message.trailersDistinct#

类似于 message.trailers,但没有合并逻辑,并且值始终是字符串数组,即使对于只接收一次的标头也是如此。仅在 'end' 事件时填充。

message.url#

仅对从 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: 'https:///status?name=ryan',
  origin: 'https://',
  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 标头。

类:http.OutgoingMessage#

此类作为 http.ClientRequesthttp.ServerResponse 的父类。从 HTTP 事务参与者的角度来看,它是一个抽象的传出消息。

事件:'drain'#

当消息的缓冲区再次空闲时发出。

事件:'finish'#

当传输成功完成时发出。

事件:'prefinish'#

在调用 outgoingMessage.end() 之后发出。当事件发出时,所有数据都已处理,但不一定完全刷新。

outgoingMessage.addTrailers(headers)#

向消息添加 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.appendHeader(name, value)#

向标头对象追加单个标头值。

如果值是一个数组,这等同于多次调用此方法。

如果该标头之前没有值,这等同于调用 outgoingMessage.setHeader(name, value)

根据创建客户端请求或服务器时 options.uniqueHeaders 的值,这将导致标头被多次发送,或仅发送一次,值用 ; 连接。

outgoingMessage.connection#

稳定性:0 - 已弃用:请改用 outgoingMessage.socket

outgoingMessage.socket 的别名。

outgoingMessage.cork()#

参见 writable.cork()

outgoingMessage.destroy([error])#

  • error <Error> 可选,一个随 error 事件发出的错误
  • 返回:<this>

销毁消息。一旦套接字与消息关联并连接,该套接字也将被销毁。

outgoingMessage.end(chunk[, encoding][, callback])#

完成传出消息。如果主体的任何部分未发送,它将把它们刷新到底层系统。如果消息是分块的,它将发送终止块 0\r\n\r\n,并发送尾部(如果有)。

如果指定了 chunk,它等同于调用 outgoingMessage.write(chunk, encoding),然后调用 outgoingMessage.end(callback)

如果提供了 callback,它将在消息完成时被调用(等同于 'finish' 事件的监听器)。

outgoingMessage.flushHeaders()#

刷新消息头。

出于效率原因,Node.js 通常会缓冲消息头,直到调用 outgoingMessage.end() 或写入第一块消息数据。然后它会尝试将标头和数据打包到一个 TCP 数据包中。

这通常是期望的行为(它节省了一次 TCP 往返),但当第一份数据可能在很久之后才发送时则不然。outgoingMessage.flushHeaders() 绕过了这种优化并启动消息发送。

outgoingMessage.getHeader(name)#

获取具有给定名称的 HTTP 标头的值。如果未设置该标头,则返回值为 undefined

outgoingMessage.getHeaderNames()#

返回一个包含当前传出标头唯一名称的数组。所有名称均为小写。

outgoingMessage.getHeaders()#

返回当前传出标头的浅拷贝。由于使用了浅拷贝,数组值可以在不额外调用各种与标头相关的 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'] } 

outgoingMessage.hasHeader(name)#

如果由 name 标识的标头当前设置在传出标头中,则返回 true。标头名称不区分大小写。

const hasContentType = outgoingMessage.hasHeader('content-type'); 

outgoingMessage.headersSent#

只读。如果标头已发送,则为 true,否则为 false

outgoingMessage.pipe()#

覆盖从旧版 Stream 类继承的 stream.pipe() 方法,该类是 http.OutgoingMessage 的父类。

调用此方法将抛出一个 Error,因为 outgoingMessage 是一个只写流。

outgoingMessage.removeHeader(name)#

移除一个已排队等待隐式发送的标头。

outgoingMessage.removeHeader('Content-Encoding'); 

outgoingMessage.setHeader(name, value)#

设置单个标头值。如果标头已存在于待发送的标头中,其值将被替换。使用字符串数组可发送多个同名标头。

outgoingMessage.setHeaders(headers)#

为隐式标头设置多个标头值。headers 必须是 HeadersMap 的实例,如果标头已存在于待发送的标头中,其值将被替换。

const headers = new Headers({ foo: 'bar' });
outgoingMessage.setHeaders(headers); 

const headers = new Map([['foo', 'bar']]);
outgoingMessage.setHeaders(headers); 

当使用 outgoingMessage.setHeaders() 设置标头时,它们将与传递给 response.writeHead() 的任何标头合并,其中传递给 response.writeHead() 的标头具有优先权。

// Returns 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');
}); 

outgoingMessage.setTimeout(msecs[, callback])#

  • msecs <number>
  • callback <Function> 可选函数,在超时发生时调用。与绑定到 timeout 事件相同。
  • 返回:<this>

一旦套接字与消息关联并连接,将以 msecs 作为第一个参数调用 socket.setTimeout()

outgoingMessage.socket#

对底层套接字的引用。通常,用户不希望访问此属性。

调用 outgoingMessage.end() 后,此属性将置为 null。

outgoingMessage.uncork()#

参见 writable.uncork()

outgoingMessage.writableCorked#

outgoingMessage.cork() 已被调用的次数。

outgoingMessage.writableEnded#

如果 outgoingMessage.end() 已被调用,则为 true。此属性不表示数据是否已刷新。为此,请改用 message.writableFinished

outgoingMessage.writableFinished#

如果所有数据都已刷新到底层系统,则为 true

outgoingMessage.writableHighWaterMark#

如果已分配,则为底层套接字的 highWaterMark。否则,为当 writable.write() 开始返回 false 时的默认缓冲区级别 (16384)。

outgoingMessage.writableLength#

缓冲的字节数。

outgoingMessage.writableObjectMode#

始终为 false

outgoingMessage.write(chunk[, encoding][, callback])#

发送一块主体。此方法可以多次调用。

encoding 参数仅在 chunk 是字符串时相关。默认为 'utf8'

callback 参数是可选的,当此数据块被刷新时将被调用。

如果全部数据已成功刷新到内核缓冲区,则返回 true。如果全部或部分数据已在用户内存中排队,则返回 false。当缓冲区再次空闲时,将发出 'drain' 事件。

http.METHODS#

解析器支持的 HTTP 方法列表。

http.STATUS_CODES#

所有标准 HTTP 响应状态码及其简短描述的集合。例如,http.STATUS_CODES[404] === 'Not Found'

http.createServer([options][, requestListener])#

  • options <Object>

    • connectionsCheckingInterval: 设置检查未完成请求中请求和标头超时的间隔值(以毫秒为单位)。默认值: 30000
    • headersTimeout:设置从客户端接收完整 HTTP 头的超时值(以毫秒为单位)。有关更多信息,请参阅 server.headersTimeout默认值:60000
    • highWaterMark <number> 可选地覆盖所有 socketreadableHighWaterMarkwritableHighWaterMark。这会影响 IncomingMessageServerResponsehighWaterMark 属性。默认值: 参见 stream.getDefaultHighWaterMark()
    • insecureHTTPParser <boolean> 如果设置为 true,它将使用一个启用了宽松标志的 HTTP 解析器。应避免使用不安全的解析器。有关更多信息,请参阅 --insecure-http-parser默认值: false
    • IncomingMessage <http.IncomingMessage> 指定要使用的 IncomingMessage 类。用于扩展原始的 IncomingMessage默认值: IncomingMessage
    • joinDuplicateHeaders <boolean> 如果设置为 true,此选项允许将请求中多个标头的字段行值用逗号 (, ) 连接起来,而不是丢弃重复项。有关更多信息,请参阅 message.headers默认值: false
    • keepAlive <boolean> 如果设置为 true,它会在收到新的传入连接后立即在套接字上启用 keep-alive 功能,类似于 [socket.setKeepAlive([enable][, initialDelay])][socket.setKeepAlive(enable, initialDelay)] 中的操作。默认值: false
    • keepAliveInitialDelay <number> 如果设置为正数,它会设置在空闲套接字上发送第一个 keepalive 探测之前的初始延迟。默认值: 0
    • keepAliveTimeout: 服务器在完成写入最后一个响应后,需要等待额外传入数据的非活动毫秒数,之后套接字将被销毁。有关更多信息,请参阅 server.keepAliveTimeout默认值: 5000
    • maxHeaderSize <number> 可选地覆盖此服务器接收的请求的 --max-http-header-size 值,即请求头的最大长度(以字节为单位)。默认值: 16384 (16 KiB)。
    • noDelay <boolean> 如果设置为 true,它会在收到新的传入连接后立即禁用 Nagle 算法。默认值: true
    • requestTimeout:设置从客户端接收整个请求的超时值(以毫秒为单位)。有关更多信息,请参阅 server.requestTimeout默认值:300000
    • requireHostHeader <boolean> 如果设置为 true,它会强制服务器对任何缺少 Host 标头的 HTTP/1.1 请求消息响应 400 (Bad Request) 状态码(根据规范要求)。默认值:true
    • ServerResponse <http.ServerResponse> 指定要使用的 ServerResponse 类。用于扩展原始的 ServerResponse默认值: ServerResponse
    • shouldUpgradeCallback(request) <Function> 一个回调函数,它接收一个传入请求并返回一个布尔值,以控制应接受哪些升级尝试。接受的升级将触发一个 'upgrade' 事件(或者如果没有注册监听器,它们的套接字将被销毁),而被拒绝的升级将像任何非升级请求一样触发一个 'request' 事件。此选项默认为 () => server.listenerCount('upgrade') > 0
    • uniqueHeaders <Array> 一个响应标头列表,这些标头只应发送一次。如果标头的值是一个数组,这些项将使用 ; 连接。
    • rejectNonStandardBodyWrites <boolean> 如果设置为 true,当写入一个没有主体的 HTTP 响应时会抛出错误。默认值: false
  • requestListener <Function>

  • 返回:<http.Server>

返回 http.Server 的一个新实例。

requestListener 是一个自动添加到 'request' 事件的函数。

import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);

http.get(options[, callback])#

http.get(url[, options][, callback])#

由于大多数请求都是没有主体的 GET 请求,Node.js 提供了这个便捷方法。此方法与 http.request() 的唯一区别是它默认将方法设置为 GET 并自动调用 req.end()。回调函数必须注意消费响应数据,原因在 http.ClientRequest 部分有说明。

callback 被调用时带有一个参数,该参数是 http.IncomingMessage 的实例。

JSON 获取示例:

http.get('https://:8000/', (res) => {
  const { statusCode } = res;
  const contentType = res.headers['content-type'];

  let error;
  // Any 2xx status code signals 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 from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000); 

http.globalAgent#

Agent 的全局实例,用作所有 HTTP 客户端请求的默认值。与默认 Agent 配置的不同之处在于,它启用了 keepAlive 并且超时时间为 5 秒。

http.maxHeaderSize#

只读属性,指定 HTTP 标头允许的最大大小(以字节为单位)。默认为 16 KiB。可使用 --max-http-header-size CLI 选项进行配置。

对于服务器和客户端请求,可以通过传递 maxHeaderSize 选项来覆盖此值。

http.request(options[, callback])#

http.request(url[, options][, callback])#

  • url <string> | <URL>
  • options <Object>
    • agent <http.Agent> | <boolean> 控制 Agent 的行为。可能的值:
      • undefined(默认):为此主机和端口使用 http.globalAgent
      • Agent 对象:显式使用传入的 Agent
      • false: 导致使用一个新的具有默认值的 Agent
    • auth <string> 基本身份验证('user:password')用于计算 Authorization 标头。
    • createConnection <Function> 一个函数,在不使用 agent 选项时,为请求生成一个套接字/流。这可以用来避免仅仅为了覆盖默认的 createConnection 函数而创建一个自定义的 Agent 类。有关更多详细信息,请参阅 agent.createConnection()。任何 Duplex 流都是有效的返回值。
    • defaultPort <number> 协议的默认端口。默认值: 如果使用 Agent,则为 agent.defaultPort,否则为 undefined
    • family <number> 解析 hosthostname 时使用的 IP 地址族。有效值为 46。如果未指定,将同时使用 IP v4 和 v6。
    • headers <Object> | <Array> 包含请求头的对象或字符串数组。数组的格式与 message.rawHeaders 相同。
    • hints <number> 可选的 dns.lookup() 提示
    • host <string> 发出请求的服务器的域名或 IP 地址。默认值: 'localhost'
    • hostname <string> host 的别名。为了支持 url.parse(),如果同时指定了 hosthostname,将使用 hostname
    • insecureHTTPParser <boolean> 如果设置为 true,它将使用一个启用了宽松标志的 HTTP 解析器。应避免使用不安全的解析器。有关更多信息,请参阅 --insecure-http-parser默认值: false
    • joinDuplicateHeaders <boolean> 它将请求中多个标头的字段行值用 , 连接起来,而不是丢弃重复项。有关更多信息,请参阅 message.headers默认值: false
    • localAddress <string> 用于绑定网络连接的本地接口。
    • localPort <number> 连接的本地端口。
    • lookup <Function> 自定义查找函数。默认值: dns.lookup()
    • maxHeaderSize <number> 可选地覆盖从服务器接收的响应的 --max-http-header-size 值(响应头的最大长度,以字节为单位)。默认值: 16384 (16 KiB)。
    • method <string> 一个指定 HTTP 请求方法的字符串。默认值: 'GET'
    • path <string> 请求路径。应包含查询字符串(如果有)。例如 '/index.html?page=12'。当请求路径包含非法字符时会抛出异常。目前只有空格被拒绝,但将来可能会改变。默认值: '/'
    • port <number> 远程服务器的端口。默认值: 如果设置了 defaultPort,则为该值,否则为 80
    • protocol <string> 使用的协议。默认值: 'http:'
    • setDefaultHeaders <boolean>: 指定是否自动添加默认标头,如 ConnectionContent-LengthTransfer-EncodingHost。如果设置为 false,则所有必需的标头都必须手动添加。默认为 true
    • setHost <boolean>: 指定是否自动添加 Host 标头。如果提供,此选项将覆盖 setDefaultHeaders。默认为 true
    • signal <AbortSignal>: 一个可用于中止正在进行的请求的 AbortSignal。
    • socketPath <string> Unix 域套接字。如果指定了 hostport 之一,则不能使用,因为它们指定了 TCP 套接字。
    • timeout <number>: 一个以毫秒为单位指定套接字超时的数字。这将在套接字连接之前设置超时。
    • uniqueHeaders <Array> 一个请求标头列表,这些标头只应发送一次。如果标头的值是一个数组,这些项将使用 ; 连接。
  • callback <Function>
  • 返回:<http.ClientRequest>

也支持 socket.connect() 中的 options

Node.js 为每个服务器维护多个连接以发出 HTTP 请求。此函数允许透明地发出请求。

url 可以是字符串或 URL 对象。如果 url 是一个字符串,它会使用 new URL() 自动解析。如果它是一个 URL 对象,它将被自动转换为一个普通的 options 对象。

如果同时指定了 urloptions,对象将被合并,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(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on('end', () => {
    console.log('No more data in response.');
  });
});

req.on('error', (e) => {
  console.error(`problem with request: ${e.message}`);
});

// Write data to request body
req.write(postData);
req.end();const http = require('node:http');

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(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on('end', () => {
    console.log('No more data in response.');
  });
});

req.on('error', (e) => {
  console.error(`problem with request: ${e.message}`);
});

// Write data to request body
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',例如在大多数重定向中)
    • res 对象上的 'end'
  • 'close'

如果发生连接错误,将发出以下事件:

  • 'socket'
  • 'error'
  • 'close'

如果在收到响应之前连接过早关闭,将按以下顺序发出以下事件:

  • 'socket'
  • 'error',错误信息为 'Error: socket hang up',代码为 'ECONNRESET'
  • 'close'

如果在收到响应后连接过早关闭,将按以下顺序发出以下事件:

  • 'socket'
  • 'response'
    • res 对象上的 'data' 任意次数
  • (连接在此处关闭)
  • res 对象上的 'aborted'
  • 'close'
  • res 对象上的 'error',错误信息为 'Error: aborted',代码为 'ECONNRESET'
  • res 对象上的 'close'

如果在分配套接字之前调用 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'
    • res 对象上的 'data' 任意次数
  • (在此处调用 req.destroy()
  • res 对象上的 'aborted'
  • 'close'
  • res 对象上的 'error',错误信息为 'Error: aborted',代码为 'ECONNRESET',或者调用 req.destroy() 时传入的错误
  • res 对象上的 'close'

如果在分配套接字之前调用 req.abort(),将按以下顺序发出以下事件:

  • (在此处调用 req.abort()
  • 'abort'
  • 'close'

如果在连接成功之前调用 req.abort(),将按以下顺序发出以下事件:

  • 'socket'
  • (在此处调用 req.abort()
  • 'abort'
  • 'error',错误信息为 'Error: socket hang up',代码为 'ECONNRESET'
  • 'close'

如果在收到响应后调用 req.abort(),将按以下顺序发出以下事件:

  • 'socket'
  • 'response'
    • res 对象上的 'data' 任意次数
  • (在此处调用 req.abort()
  • 'abort'
  • res 对象上的 'aborted'
  • res 对象上的 'error',错误信息为 'Error: aborted',代码为 'ECONNRESET'
  • 'close'
  • res 对象上的 'close'

设置 timeout 选项或使用 setTimeout() 函数不会中止请求或做任何事情,只会添加一个 'timeout' 事件。

传递一个 AbortSignal,然后在相应的 AbortController 上调用 abort() 的行为与在请求上调用 .destroy() 相同。具体来说,将发出 'error' 事件,错误信息为 'AbortError: The operation was aborted',代码为 'ABORT_ERR',以及 cause(如果提供的话)。

http.validateHeaderName(name[, label])#

  • name <string>
  • label <string> 错误消息的标签。默认值: 'Header name'

对提供的 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 [""]'
}const { validateHeaderName } = require('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 [""]'
}

http.validateHeaderValue(name, value)#

对提供的 value 执行与调用 res.setHeader(name, value) 时相同的底层验证。

将非法值作为 value 传递将导致抛出 TypeError

  • 未定义值错误由 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); // --> 'Invalid value "undefined" for header "x-my-header"'
}

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); // --> 'Invalid character in header content ["x-my-header"]'
}const { validateHeaderValue } = require('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); // --> 'Invalid value "undefined" for header "x-my-header"'
}

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); // --> 'Invalid character in header content ["x-my-header"]'
}

http.setMaxIdleHTTPParsers(max)#

设置空闲 HTTP 解析器的最大数量。

类:WebSocket#

<WebSocket> 的浏览器兼容实现。

内置代理支持#

稳定性:1.1 - 活跃开发

当 Node.js 创建全局代理时,如果设置了 NODE_USE_ENV_PROXY 环境变量为 1 或启用了 --use-env-proxy,全局代理将使用 proxyEnv: process.env 构建,从而根据环境变量启用代理支持。也可以通过在构造代理时传递 proxyEnv 选项来创建具有代理支持的自定义代理。如果只想从环境变量继承配置,该值可以是 process.env,或者是一个具有覆盖环境的特定设置的对象。

检查 proxyEnv 的以下属性来配置代理支持。

  • HTTP_PROXYhttp_proxy: HTTP 请求的代理服务器 URL。如果两者都设置了,http_proxy 优先。
  • HTTPS_PROXYhttps_proxy: HTTPS 请求的代理服务器 URL。如果两者都设置了,https_proxy 优先。
  • NO_PROXYno_proxy: 逗号分隔的绕过代理的主机列表。如果两者都设置了,no_proxy 优先。

如果请求是向 Unix 域套接字发出的,代理设置将被忽略。

代理 URL 格式#

代理 URL 可以使用 HTTP 或 HTTPS 协议:

  • HTTP 代理: http://proxy.example.com:8080
  • HTTPS 代理: https://proxy.example.com:8080
  • 带身份验证的代理: http://username:password@proxy.example.com:8080

NO_PROXY 格式#

NO_PROXY 环境变量支持多种格式

  • * - 为所有主机绕过代理
  • 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.js 进程,并为通过默认全局代理发送的所有请求启用代理支持,可以使用 NODE_USE_ENV_PROXY 环境变量

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 

要创建一个具有内置代理支持的自定义代理

const http = require('node:http');

// Creating a custom agent with custom proxy support.
const agent = new http.Agent({ proxyEnv: { HTTP_PROXY: 'http://proxy.example.com:8080' } });

http.request({
  hostname: 'www.example.com',
  port: 80,
  path: '/',
  agent,
}, (res) => {
  // This request will be proxied through proxy.example.com:8080 using the HTTP protocol.
  console.log(`STATUS: ${res.statusCode}`);
}); 

另外,以下方法也同样有效

const http = require('node:http');
// Use lower-cased option name.
const agent1 = new http.Agent({ proxyEnv: { http_proxy: 'http://proxy.example.com:8080' } });
// Use values inherited from the environment variables, if the process is started with
// HTTP_PROXY=http://proxy.example.com:8080 this will use the proxy server specified
// in process.env.HTTP_PROXY.
const agent2 = new http.Agent({ proxyEnv: process.env });