On this page

HTTPS

History
Source Code: lib/https.js

稳定性:2 - 稳定

HTTPS 是基於 TLS/SSL 的 HTTP 協議。在 Node.js 中,這是作為一個單獨的模塊實現的。

Node.js 有可能在不包含 node:crypto 模塊支持的情況下構建。在這種情況下,嘗試從 https import 或調用 require('node:https') 將導致拋出錯誤。

使用 CommonJS 時,拋出的錯誤可以使用 try/catch 捕獲:

let https;
try {
  https = require('node:https');
} catch (err) {
  console.error('https support is disabled!');
}

使用詞法 ESM import 關鍵字時,只有在嘗試加載模塊_之前_註冊了 process.on('uncaughtException') 的處理程序(例如,使用預加載模塊),才能捕獲錯誤。

使用 ESM 時,如果代碼有可能在尚未啟用 crypto 支持的 Node.js 構建上運行,請考慮使用 import() 函數而不是詞法 import 關鍵字:

let https;
try {
  https = await import('node:https');
} catch (err) {
  console.error('https support is disabled!');
}

一個用於 HTTPS 的 Agent 對象,類似於 http.Agent。詳見 https.request() 獲取更多信息。

類似於 http.AgentcreateConnection(options[, callback]) 方法可以被重寫以自定義 TLS 連接的建立方式。

詳見 agent.createConnection() 了解重寫此方法的詳細信息,包括使用回調異步創建 socket。

new Agent(options?): void
Attributes
options:<Object>
要在 agent 上設置的可配置選項集。 可以擁有與  http.Agent(options) 相同的字段,以及
maxCachedSessions:<number>
TLS 緩存會話的最大數量。 使用  0 禁用 TLS 會話緩存。 默認值: 100
servername:<string>
要發送到服務器的  服務器名稱指示擴展 的值。使用 空字符串 '' 禁用發送該擴展。 默認值: 目標服務器的主機名,除非目標服務器是使用 IP 地址指定的,在這種情況下默認值是 '' (無擴展)。

事件:'keylog'

History
  • line {Buffer} ASCII 文本行,採用 NSS SSLKEYLOGFILE 格式。
  • tlsSocket <tls.TLSSocket> 生成該事件的 tls.TLSSocket 實例。

當由此 agent 管理的連接生成或接收密鑰材料時,會發出 keylog 事件(通常在手握完成之前,但不一定)。此密鑰材料可以存儲用於調試,因為它允許解密捕獲的 TLS 流量。每個 socket 可能會發出多次。

一個典型的用例是將接收到的行追加到一個公共文本文件中,該軟件(例如 Wireshark)稍後使用該文件來解密流量:

// ...
https.globalAgent.on('keylog', (line, tlsSocket) => {
  fs.appendFileSync('/tmp/ssl-keys.log', line, { mode: 0o600 });
});

類:https.Server

History

詳見 http.Server 獲取更多信息。

M

server.close

History
server.close(callback?): void
Attributes
callback:<Function>
返回: <https.Server>

詳見 node:http 模塊中的 server.close()

server[Symbol.asyncDispose](): void

調用 server.close() 並返回一個 promise,當服務器關閉時該 promise 會 fulfilled。

M

server.closeAllConnections

History
server.closeAllConnections(): void

詳見 node:http 模塊中的 server.closeAllConnections()

M

server.closeIdleConnections

History
server.closeIdleConnections(): void

詳見 node:http 模塊中的 server.closeIdleConnections()

P

server.headersTimeout

History

詳見 node:http 模塊中的 server.headersTimeout

server.listen(): void

啟動 HTTPS 服務器監聽加密連接。 此方法等同於 net.Server 中的 server.listen()

詳見 node:http 模塊中的 server.maxHeadersCount

  • 類型:<number> 默認值: 300000

詳見 node:http 模塊中的 server.requestTimeout

M

server.setTimeout

History
server.setTimeout(msecs?, callback?): void
Attributes
msecs:<number>
默認值: 120000 (2 分鐘)
callback:<Function>
返回: <https.Server>

詳見 node:http 模塊中的 server.setTimeout()

  • 類型:<number> 默認值: 0(無超時)

詳見 node:http 模塊中的 server.timeout

P

server.keepAliveTimeout

History
  • 類型:<number> 默認值: 5000(5 秒)

詳見 node:http 模塊中的 server.keepAliveTimeout

M

https.createServer

History
https.createServer(options?, requestListener?): void
Attributes
options:<Object>
requestListener:<Function>
要添加到  'request' 事件的監聽器。
返回: <https.Server>
// curl -k https://localhost:8000/
import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem'),
};

createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);

import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  pfx: readFileSync('test_cert.pfx'),
  passphrase: 'sample',
};

createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);

要為此示例生成證書和密鑰,請運行:

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
  -keyout private-key.pem -out certificate.pem

然後,要為此示例生成 pfx 證書,請運行:

openssl pkcs12 -certpbe AES-256-CBC -export -out test_cert.pfx \
  -inkey private-key.pem -in certificate.pem -passout pass:sample
https.get(options, callback?): void
https.get(url, options?, callback?): void
Attributes
options:<Object> | <string> | <URL>
接受與  https.request() 相同的 options ,默認方法設置為 GET。
callback:<Function>

類似於 http.get() 但用於 HTTPS。

options 可以是一個對象、一個字符串或一個 URL 對象。如果 options 是字符串,它會自動被 new URL() 解析。如果它是 URL 對象,它將自動轉換為普通 options 對象。

import { get } from 'node:https';
import process from 'node:process';

get('https://encrypted.google.com/', (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});

所有 HTTPS 客戶端請求的 https.Agent 全局實例。與默認 https.Agent 配置的不同之處在於啟用了 keepAlivetimeout 為 5 秒。

https.request(options, callback?): void
https.request(url, options?, callback?): void
Attributes
options:<Object> | <string> | <URL>
接受来自  http.request() 的所有 options ,但默认值存在一些差异:
protocol?:
Default: 'https:'
port?:
Default: 443
agent?:
Default: https.globalAgent
callback:<Function>

向安全 Web 服务器发出请求。

还接受来自 tls.connect() 的以下附加 optionsca, cert, ciphers, clientCertEngine (deprecated), crl, dhparam, ecdhCurve, honorCipherOrder, key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext, highWaterMark

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

https.request() 返回 http.ClientRequest 类的一个实例。ClientRequest 实例是一个可写流。如果需要使用 POST 请求上传文件,则写入 ClientRequest 对象。

import { request } from 'node:https';
import process from 'node:process';

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
};

const req = request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});
req.end();

Example using options from tls.connect():

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
};
options.agent = new https.Agent(options);

const req = https.request(options, (res) => {
  // ...
});

Alternatively, opt out of connection pooling by not using an Agent.

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  agent: false,
};

const req = https.request(options, (res) => {
  // ...
});

Example using a URL as options:

const options = new URL('https://abc:xyz@example.com');

const req = https.request(options, (res) => {
  // ...
});

Example pinning on certificate fingerprint, or the public key (similar to pin-sha256):

import { checkServerIdentity } from 'node:tls';
import { Agent, request } from 'node:https';
import { createHash } from 'node:crypto';

function sha256(s) {
  return createHash('sha256').update(s).digest('base64');
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function(host, cert) {
    // 确保证书是颁发给我们所连接的主机的
    const err = checkServerIdentity(host, cert);
    if (err) {
      return err;
    }

    // 锁定公钥,类似于 HPKP pin-sha256 锁定
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=';
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg = 'Certificate verification error: ' +
        `The public key of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // 锁定确切的证书,而不是公钥
    const cert256 = 'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' +
      '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65';
    if (cert.fingerprint256 !== cert256) {
      const msg = 'Certificate verification error: ' +
        `The certificate of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // 此循环仅用于提供信息。
    // 打印链中所有证书的证书和公钥指纹
    //。通常在公共互联网上锁定颁发者的公钥,
    // 而在敏感环境中锁定服务的公钥。
    let lastprint256;
    do {
      console.log('Subject Common Name:', cert.subject.CN);
      console.log('  Certificate SHA256 fingerprint:', cert.fingerprint256);

      const hash = createHash('sha256');
      console.log('  Public key ping-sha256:', sha256(cert.pubkey));

      lastprint256 = cert.fingerprint256;
      cert = cert.issuerCertificate;
    } while (cert.fingerprint256 !== lastprint256);

  },
};

options.agent = new Agent(options);
const req = request(options, (res) => {
  console.log('All OK. Server matched our pinned cert or public key');
  console.log('statusCode:', res.statusCode);

  res.on('data', (d) => {});
});

req.on('error', (e) => {
  console.error(e.message);
});
req.end();

Outputs for example:

Subject Common Name: github.com
  Certificate SHA256 fingerprint: FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65
  Public key ping-sha256: SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=
Subject Common Name: Sectigo ECC Domain Validation Secure Server CA
  Certificate SHA256 fingerprint: 61:E9:73:75:E9:F6:DA:98:2F:F5:C1:9E:2F:94:E6:6C:4E:35:B6:83:7C:E3:B9:14:D2:24:5C:7F:5F:65:82:5F
  Public key ping-sha256: Eep0p/AsSa9lFUH6KT2UY+9s1Z8v7voAPkQ4fGknZ2g=
Subject Common Name: USERTrust ECC Certification Authority
  Certificate SHA256 fingerprint: A6:CF:64:DB:B4:C8:D5:FD:19:CE:48:89:60:68:DB:03:B5:33:A8:D1:33:6C:62:56:A8:7D:00:CB:B3:DE:F3:EA
  Public key ping-sha256: UJM2FOhG9aTNY0Pg4hgqjNzZ/lQBiMGRxPD5Y2/e0bw=
Subject Common Name: AAA Certificate Services
  Certificate SHA256 fingerprint: D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4
  Public key ping-sha256: vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=
All OK. Server matched our pinned cert or public key
statusCode: 200