On this page

稳定性: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。

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

詳見 http.Server 獲取更多資訊。

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

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

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

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

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

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

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

Attributes
options:<Object>
requestListener:<Function>
要添加到  'request' 事件的监听器。
// 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
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 秒。

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

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

还接受来自 tls.connect() 的以下附加 optionsca, cert, ciphers, clientCertEngine (已弃用), 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();

使用 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) => {
  // ...
});

或者,通过不使用 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) => {
  // ...
});

使用 URL 作为 options 的示例:

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

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

证书指纹上的示例固定,或公钥上的示例固定(类似于 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();

例如输出:

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