HTTP#

穩定性: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', '*/*' ]

類:http.Agent#

Agent 負責管理 HTTP 客戶端的連線永續性和重用。它為給定的主機和埠維護一個待處理請求佇列,重用單個套接字連線直到佇列為空。此時,套接字要麼被銷燬,要麼放入池中以供後續對同一主機和埠的請求使用。是否銷燬或池化取決於 keepAlive 選項

池化連線啟用了 TCP Keep-Alive,但伺服器仍可能關閉空閒連線,在這種情況下它們將從池中移除,並在為該主機和埠發出新的 HTTP 請求時建立新連線。伺服器也可能拒絕在同一連線上允許多個請求,在這種情況下,必須為每個請求重新建立連線且無法池化。Agent 仍會向該伺服器發出請求,但每個請求都將透過新連線進行。

當連線被客戶端或伺服器關閉時,它將從池中移除。池中任何未使用的套接字都將被取消引用(unref),以便在沒有未完成請求時不會保持 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 頭,或者 keepAlivemaxSockets 選項分別設定為 falseInfinity(此時將使用 Connection: close),否則始終會發送 Connection: keep-alive 頭。預設: 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])#

  • options <Object> 包含連線詳細資訊的選項。檢查 net.createConnection() 以瞭解選項格式。對於自定義代理,此物件會傳遞給自定義 createConnection 函式。
  • callback <Function> (可選,主要用於自定義代理)當套接字建立時由自定義 createConnection 實現呼叫的函式,特別適用於非同步操作。
  • 返回:<stream.Duplex> 已建立的套接字。這是由預設實現或自定義同步 createConnection 實現返回的。如果自定義 createConnection 使用 callback 進行非同步操作,則此返回值可能不是獲取套接字的主要方式。

產生一個用於 HTTP 請求的套接字/流。

預設情況下,此函式的行為與 net.createConnection() 完全相同,同步返回已建立的套接字。此預設實現使用簽名中的可選 callback 引數。

但是,自定義代理可以覆蓋此方法以提供更大的靈活性,例如非同步建立套接字。覆蓋 createConnection

  1. 同步套接字建立:覆蓋方法可以直接返回套接字/流。
  2. 非同步套接字建立:覆蓋方法可以接受 callback 並將建立的套接字/流傳遞給它(例如 callback(null, newSocket))。如果在套接字建立過程中發生錯誤,它應作為第一個引數傳遞給 callback(例如 callback(err))。

代理將使用 options 和此內部 callback 呼叫提供的 createConnection 函式。代理提供的 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。確定代理每個源(origin)可以開啟多少個併發套接字。源是 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 設定為 true,則與 Content-Length 頭值不匹配會導致丟擲 Error,其程式碼為 '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 請求/響應鏈,例如 web sockets、就地 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, 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 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, stream, upgradeHead) => {
    console.log('got upgraded!');
    stream.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, 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 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, stream, upgradeHead) => {
    console.log('got upgraded!');
    stream.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';
const agent = new http.Agent({ keepAlive: true });

// 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
const http = require('node:http');
const agent = new http.Agent({ keepAlive: true });

// 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 選項更精確地控制這一點。

監聽此事件是可選的,客戶端不能堅持更改協議。

如果 shouldUpgradeCallback 接受了升級但未註冊事件處理程式,則套接字將被銷燬,導致客戶端立即關閉連線。

在傳入請求帶有正文的不常見情況下,此正文將像往常一樣被解析,與升級流分開,並且原始流資料僅在完成後才會開始。為確保從流讀取不會因等待讀取請求正文而受阻,對流的任何讀取都會自動啟動請求正文的流動。如果你想讀取請求正文,請確保在開始從升級後的流讀取之前執行此操作(即附加 'data' 監聽器)。

流引數通常是請求使用的 <net.Socket> 例項,但在某些情況下(例如帶有請求正文時),它可能是一個雙工流。如果需要,你可以透過 request.socket 訪問請求底層的原始連線,除非使用者指定了其他套接字型別,否則它保證是 <net.Socket> 的例項。

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])#

設定套接字的超時值,如果發生超時,則在 Server 物件上發出 'timeout' 事件,並將套接字作為引數傳遞。

如果 Server 物件上有 '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 頭(詳見 RFC 9110 第 6.6.1 節)。

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])#

將套接字的超時值設定為 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,其程式碼為 '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 響應的一部分寫入主體,則會丟擲一個程式碼為 ERR_HTTP_BODY_NOT_ALLOWED 的同步 Error

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])#

向客戶端傳送帶有 Link 標頭的 HTTP/1.1 103 Early Hints 訊息,指示使用者代理可以預載入/預連線連結的資源。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 可以是一個 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()

// 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' 事件。它可用於訪問響應狀態、標頭和資料。

不同於其作為 <stream.Duplex> 子類的 socket 值,IncomingMessage 本身繼承自 <stream.Readable>,並單獨建立以解析和傳送傳入的 HTTP 標頭和有效載荷,因為在 keep-alive 的情況下,底層套接字可能會被多次重用。

事件:'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> 之外的套接字型別或內部已將其置空。

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()#

重寫從作為 http.OutgoingMessage 父類的遺留 Stream 類繼承的 stream.pipe() 方法。

呼叫此方法將丟擲 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>

一旦套接字與訊息關聯並已連線,將呼叫 socket.setTimeout(),並將 msecs 作為第一個引數。

outgoingMessage.socket#

對底層套接字的引用。通常,使用者不需要訪問此屬性。

呼叫 outgoingMessage.end() 後,此屬性將被置空。

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
    • optimizeEmptyRequests <boolean> 如果設定為 true,則沒有 Content-LengthTransfer-Encoding 標頭(表示沒有主體)的請求將使用已結束的主體流進行初始化,因此它們永遠不會觸發任何流事件(如 'data''end')。您可以使用 req.readableEnded 來檢測此情況。預設值: 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'
      • '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(如果有)。

    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 解析器的最大數量。

    http.setGlobalProxyFromEnv([proxyEnv])#

    • proxyEnv <Object> 包含代理配置的物件。它接受與 Agent 接受的 proxyEnv 選項相同的選項。預設值: process.env
    • 返回:<Function> 一個函式,用於將原始代理和排程程式設定恢復到呼叫此 http.setGlobalProxyFromEnv() 之前的狀態。

    在執行時動態重置全域性配置以啟用對 fetch()http.request()/https.request() 的內建代理支援,作為使用 --use-env-proxy 標誌或 NODE_USE_ENV_PROXY 環境變數的替代方法。它也可以用於覆蓋從環境變數配置的設定。

    由於此函式會重置全域性配置,因此在呼叫此函式後,任何先前配置的 http.globalAgenthttps.globalAgent 或 undici 全域性排程程式都將被覆蓋。建議在發出任何請求之前呼叫它,並避免在請求過程中呼叫它。

    有關代理 URL 格式和 NO_PROXY 語法的詳細資訊,請參閱 內建代理支援

    類:WebSocket#

    <WebSocket> 的瀏覽器相容實現。

    內建代理支援#

    穩定性:1.1 - 活躍開發中

    當 Node.js 建立全域性代理時,如果設定了 NODE_USE_ENV_PROXY 環境變數為 1 或啟用了 --use-env-proxy,則全域性代理將使用 proxyEnv: process.env 進行構造,從而根據環境變數啟用代理支援。

    要動態且全域性地啟用代理支援,請使用 http.setGlobalProxyFromEnv()

    自定義代理也可以透過在構建代理時傳遞 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
    

    要使用 process.envhttp.setGlobalProxyFromEnv() 的預設選項)動態且全域性地啟用代理支援

    const http = require('node:http');
    
    // Reads proxy-related environment variables from process.env
    const restore = http.setGlobalProxyFromEnv();
    
    // Subsequent requests will use the configured proxies from environment variables
    http.get('http://www.example.com', (res) => {
      // This request will be proxied if HTTP_PROXY or http_proxy is set
    });
    
    fetch('https://www.example.com', (res) => {
      // This request will be proxied if HTTPS_PROXY or https_proxy is set
    });
    
    // To restore the original global agent and dispatcher settings, call the returned function.
    // restore();
    import http from 'node:http';
    
    // Reads proxy-related environment variables from process.env
    http.setGlobalProxyFromEnv();
    
    // Subsequent requests will use the configured proxies from environment variables
    http.get('http://www.example.com', (res) => {
      // This request will be proxied if HTTP_PROXY or http_proxy is set
    });
    
    fetch('https://www.example.com', (res) => {
      // This request will be proxied if HTTPS_PROXY or https_proxy is set
    });
    
    // To restore the original global agent and dispatcher settings, call the returned function.
    // 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',
    });
    
    // Subsequent requests will use the configured proxies
    http.get('http://www.example.com', (res) => {
      // This request will be proxied through proxy.example.com:8080
    });
    
    fetch('https://www.example.com', (res) => {
      // This request will be proxied through proxy.example.com:8443
    });
    import http from 'node:http';
    
    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',
    });
    
    // Subsequent requests will use the configured proxies
    http.get('http://www.example.com', (res) => {
      // This request will be proxied through proxy.example.com:8080
    });
    
    fetch('https://www.example.com', (res) => {
      // This request will be proxied through proxy.example.com:8443
    });
    

    要建立具有內建代理支援的自定義代理

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