首页
/ Puppeteer SecurityDetails.issuer() 深度解析:读取 HTTPS 响应证书的签发者信息

Puppeteer SecurityDetails.issuer() 深度解析:读取 HTTPS 响应证书的签发者信息

2026-09-07 13:18:06作者:温玫谨Lighthearted

HTTP 与 HTTPS 请求的响应对象是 Puppeteer 中判断页面安全性、抓取证书指纹的核心入口。本指南聚焦 SecurityDetails 类的 issuer() 方法,讲解如何从一次安全连接(TLS/HTTPS)的响应中读取服务端证书的**签发者(Issuer)**名称,并结合仓库源码(packages/puppeteer-core/src/common/SecurityDetails.ts)与真实测试用例,说明该字段在 CDP 与 WebDriver BiDi 两种协议实现下的数据来源、空值语义与实用场景。读完本篇,你将能熟练编写"访问 HTTPS 页面 → 提取证书签发者与其余安全细节"的可运行代码,并能在做证书校验、抓包分析时准确区分 issuer(签发者)与 subjectName(持有者)。

方法签名与文档定位

SecurityDetails.issuer() 属于 Puppeteer API 中 SecurityDetails 类(见 docs/api/puppeteer.securitydetails.md)的方法,其 API 参考文档位于 docs/api/puppeteer.securitydetails.issuer.md。官方对该方法的定义非常简洁:

The name of the issuer of the certificate.(证书签发者的名称)

对应的类型签名如下:

class SecurityDetails {
  issuer(): string;
}

返回值:string —— 签发该服务器证书的 CA(证书颁发机构)的名称。例如由 Let's Encrypt 签发的证书,此字段通常返回 "R3""WE1" 等中间 CA 的通用名(Common Name)。

从响应到 SecurityDetails:字段的数据来源

在进入 issuer() 之前,先弄清 SecurityDetails 对象从哪里来、何时存在。

1. 获取入口:HTTPResponse.securityDetails()

SecurityDetails 并不是独立构造出来的,而是通过 HTTPResponse.securityDetails() 方法随响应一并获得。该抽象方法的定义位于 packages/puppeteer-core/src/api/HTTPResponse.ts

/**
 * {@link SecurityDetails} if the response was received over the
 * secure connection, or `null` otherwise.
 */
abstract securityDetails(): SecurityDetails | null;

关键语义:

  • 若响应是通过**安全连接(HTTPS/TLS)**接收的,则返回一个 SecurityDetails 实例;
  • 否则(如纯 HTTP 响应)返回 null

因此使用 issuer() 前必须先判空,并可以先通过 response.fromCache()response.status() 等其它方法确认响应的整体状态。

2. 类的底层构造:直接消费 CDP 的 Network.SecurityDetails

SecurityDetails 的源码实现位于 packages/puppeteer-core/src/common/SecurityDetails.ts,它本质上是一个薄封装:构造函数接收 Chrome DevTools Protocol(CDP)的 Network.SecurityDetails 载荷,把六个字段一次性拷贝到内部私有字段中:

constructor(securityPayload: Protocol.Network.SecurityDetails) {
  this.#subjectName = securityPayload.subjectName;
  this.#issuer = securityPayload.issuer;
  this.#validFrom = securityPayload.validFrom;
  this.#validTo = securityPayload.validTo;
  this.#protocol = securityPayload.protocol;
  this.#sanList = securityPayload.sanList;
}

issuer() 本身只是对应字段的只读访问器:

issuer(): string {
  return this.#issuer;
}

SecurityDetails 类的构造函数被标记为 @internal,官方在类文档中明确提醒:第三方代码不应直接调用构造函数,也不应创建该类的子类。你应该始终通过响应对象获取它,而不是自己 new SecurityDetails(...)

3. 两种协议后端如何填装该对象

Puppeteer 同时支持 CDP(Chrome)与 WebDriver BiDi(Firefox/跨浏览器)两种自动化协议,两种实现对 securityDetails 的填充方式不同,这一点直接影响 issuer() 在你目标浏览器上的可用性:

CDP 实现packages/puppeteer-core/src/cdp/HTTPResponse.ts)——Chrome/Chromium 下,构造函数里直接根据响应载荷中的 securityDetails 字段决定返回对象还是 null

this.#securityDetails = responsePayload.securityDetails
  ? new SecurityDetails(responsePayload.securityDetails)
  : null;

WebDriver BiDi 实现packages/puppeteer-core/src/bidi/HTTPResponse.ts)——在 Firefox 等通过 BiDi 协议连接的浏览器中,安全细节通过非标准扩展字段 goog:securityDetails 传递,且仅当底层连接支持 CDP 兼容能力(cdpSupported)时才可用:

// @ts-expect-error non-standard property.
const securityDetails = data['goog:securityDetails'];
if (cdpSupported && securityDetails) {
  this.#securityDetails = new SecurityDetails(
    securityDetails as Protocol.Network.SecurityDetails,
  );
}

进一步地,在 BiDi 的 securityDetails() 访问器 中,若连接不支持该扩展,直接调用会抛出 UnsupportedOperation。这意味着:在 Firefox 上通过 WebDriver BiDi 访问 issuer() 依赖浏览器对 goog:securityDetails 的支持情况,需要针对你的目标浏览器做兼容性验证。

运行前提:自签名证书与 acceptInsecureCerts

要拿到真实的 issuer 值(尤其是对自己搭建的 HTTPS 测试服务),通常需要让浏览器接受自签名或不受信任的证书。仓库中的测试 test/src/acceptInsecureCerts.test.ts 演示了这一点:测试使用独立浏览器实例并设置 acceptInsecureCerts: true,随后访问本地 HTTPS 服务:

const state = setupSeparateTestBrowserHooks({
  acceptInsecureCerts: true,
});

也就是说,acceptInsecureCerts 等价于旧版 Puppeteer 的 ignoreHTTPSErrors,在 launch() / connect() 或创建浏览器上下文时传入即可。对公网正常签发证书的站点则无需该选项。

实战代码:读取 HTTPS 响应的证书签发者

综合以上知识,一段完整的可运行示例应包含判空与解析两个步骤:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  const response = await page.goto('https://example.com', {
    waitUntil: 'networkidle0',
  });

  if (!response) {
    throw new Error('页面未返回任何响应');
  }

  const securityDetails = response.securityDetails();
  if (securityDetails === null) {
    // 发生在非安全连接(HTTP)场景
    console.log('该响应并非通过安全连接返回,无证书信息');
  } else {
    // 核心:证书签发者
    console.log('证书签发者 (issuer):', securityDetails.issuer());
    // 便于交叉核对证书链的相关信息
    console.log('证书持有者 (subject):', securityDetails.subjectName());
    console.log('安全协议:', securityDetails.protocol());
    console.log(
      '证书有效期起始:',
      new Date(securityDetails.validFrom() * 1000).toISOString(),
    );
    console.log(
      '证书有效期截止:',
      new Date(securityDetails.validTo() * 1000).toISOString(),
    );
    console.log('主题备用名 (SANs):', securityDetails.subjectAlternativeNames());
  }
} finally {
  await browser.close();
}

几点实操提示:

  • issuer() 返回的是字符串类型,取值形如 "puppeteer-tests""Let's Encrypt" 或 CA 的通用名;
  • securityDetails() 可能返回 null(HTTP 响应),务必判空,否则直接调用 issuer() 会抛 TypeError
  • 若把 issuer()subjectName() 对比,可快速判断站点是否使用了自签名证书——自签名场景下两者通常相同;
  • 你还可以监听 page.on('response', ...) 对页面内所有子资源逐个检查其证书签发者,从而定位混合内容(mixed content)或证书异常的第三方请求。

使用测试用例印证字段语义

仓库测试 test/src/acceptInsecureCerts.test.ts 给出了该字段在真实 HTTPS 服务下的精确断言,可作为你调试自建环境时的参考基线:

const securityDetails = response!.securityDetails()!;
expect(securityDetails.issuer()).toBe('puppeteer-tests');
expect(securityDetails.protocol()).toBe(protocol);
expect(securityDetails.subjectName()).toBe('puppeteer-tests');
expect(securityDetails.validFrom()).toBe(1589357069);
expect(securityDetails.validTo()).toBe(1904717069);
expect(securityDetails.subjectAlternativeNames()).toEqual([
  'www.puppeteer-tests.test',
  'www.puppeteer-tests-1.test',
]);

从该用例可以提炼出三个要点:

  1. 自签名场景下 issuer()subjectName() 相等,均返回测试证书中的 'puppeteer-tests'
  2. 非安全请求下返回 null:同一文件中的第二个用例通过普通 HTTP server 访问页面并断言 response.securityDetails()null
  3. 重定向响应也会携带安全细节:测试覆盖了 302 重定向场景,说明只要链路经过 TLS,中间的重定向响应同样能通过 securityDetails() 拿到证书信息。

关联方法总览与使用边界

issuer() 只是 SecurityDetails 的六个成员之一,通常与其余方法配合用于完整的证书信息提取,见下表:

方法 返回类型 含义
issuer() string 证书签发者名称(本文主题)
subjectName() string 证书持有者名称(证书签发给谁)
validFrom() number 证书有效期起点的 Unix 时间戳
validTo() number 证书有效期终点的 Unix 时间戳
protocol() string 使用的安全协议,如 "TLS 1.2"
subjectAlternativeNames() string[] 证书的主题备用名(SANs)列表

这些方法的 API 文档分别位于 puppeteer.securitydetails.subjectname.mdpuppeteer.securitydetails.validfrom.mdpuppeteer.securitydetails.validto.mdpuppeteer.securitydetails.protocol.mdpuppeteer.securitydetails.subjectalternativenames.md

使用边界validFrom() / validTo() 返回的是秒级 Unix 时间戳,打印人类可读时间需先乘以 1000;SecurityDetails 本身不暴露证书的指纹、公钥等更深层信息,如需校验完整证书链或做 OCSP/CRL 检查,应把 issuer() 等字段作为输入,交由 Node.js 的 tls 模块或专用证书库完成后续工作。

小结

SecurityDetails.issuer() 是 Puppeteer 暴露服务端 TLS 证书签发者的最直接入口:响应数据经由 CDP 的 Network.SecurityDetails(Firefox 上则是 BiDi 的 goog:securityDetails 扩展)进入 packages/puppeteer-core/src/common/SecurityDetails.ts 的封装,再通过 HTTPResponse.securityDetails() 呈现给开发者。使用时牢记三点:先对 securityDetails() 判空、用 acceptInsecureCerts 支持自签名证书环境、并留意 BiDi 协议后端的能力边界——掌握这些,你就能在任何需要核验 HTTPS 连接身份的自动化场景中,精准读出证书背后的签发者。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525