Puppeteer HTTPResponse.remoteAddress() 深度解析:读取远端服务器 IP 与端口

发布时间:2026/9/8 23:30:45

Puppeteer HTTPResponse.remoteAddress() 深度解析:读取远端服务器 IP 与端口 Puppeteer HTTPResponse.remoteAddress() 深度解析读取远端服务器 IP 与端口【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer本文围绕 PuppeteerJavaScript API for Chrome and Firefox中HTTPResponse.remoteAddress()方法展开讲解其方法签名、RemoteAddress返回结构、CDP 与 WebDriver BiDi 双协议下的实现差异并结合仓库源码与测试用例给出可直接运行的监控与调试实战示例。读完本文你将掌握如何从一次真实网络响应中取得与远端服务器建立连接的 IP 地址与端口号并理解其在代理、重定向、缓存等边界场景下的取值规律。一、方法概览它返回什么HTTPResponse.remoteAddress()的定义极为简洁——The IP address and port number used to connect to the remote server用于连接远端服务器的 IP 地址与端口号。需要特别强调的是它描述的是当前响应实际与之建立 TCP 连接的远端对端地址而不是 URL 中域名解析出的逻辑地址当请求经由 HTTP 代理转发时它反映的是与代理服务器之间连接的远端地址。方法签名class HTTPResponse { abstract remoteAddress(): RemoteAddress; }该方法的 API 说明位于 puppeteer.httpresponse.remoteaddress.md它是抽象基类HTTPResponse上的抽象方法返回类型为RemoteAddress。其实际子类会根据底层自动化协议CDP 或 WebDriver BiDi给出不同的实现与数据来源下文第三节与第四节会分别拆解。RemoteAddress 返回结构export interface RemoteAddress { ip?: string; port?: number; }接口定义位于 packages/puppeteer-core/src/api/HTTPResponse.ts对应官方文档 puppeteer.remoteaddress.md。两个字段均为可选optionalip远端服务器的 IP 地址字符串可能是 IPv4如127.0.0.1或带括号的 IPv6如[::1]。port远端服务器的端口号数字。字段可选的原因有二其一部分协议如 WebDriver BiDi当前并不暴露该信息实现只能返回占位值其二某些响应如内存缓存命中可能不具备完整的连接元数据。因此消费方代码应对缺失字段做容错处理不要假定ip与port必然存在。二、在哪里获取 HTTPResponse 对象remoteAddress()是HTTPResponse实例上的方法因此获取响应对象是使用前提。常用途径有三导航返回page.goto()、page.reload()等导航方法会 resolve 为导航产生的主响应。import puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); const response await page.goto(https://example.com); if (response) { console.log(远端地址:, response.remoteAddress()); // 输出示例{ ip: 93.184.215.14, port: 443 } }注意goto()返回的response可能为null——例如跳转到about:blank、data: URL或发生错误页导航时没有可用的 HTTP 响应对象。监听事件订阅page.on(response)可以拿到页面发出的每一个子资源图片、脚本、样式表、XHR/Fetch 等对应的HTTPResponse这是做全站连接审计的入口。page.on(response, response { const {ip, port} response.remoteAddress(); console.log(${response.url()} - ${ip}:${port}); });按条件等待配合page.waitForResponse()精确捕获某个请求的响应。const response await page.waitForResponse(res res.url().includes(/api/data) ); console.log(response.remoteAddress());此外HTTPResponse.request()返回发起该响应的HTTPRequest见 puppeteer.httpresponse.request.md结合request().redirectChain()可以逐跳追溯重定向历史中每一跳的远端地址详见第六节示例。三、CDP 实现数据从哪来在 Chrome/ChromiumCDP 协议路径下响应对象由CdpHTTPResponse实现文件位于 packages/puppeteer-core/src/cdp/HTTPResponse.ts。构造函数接收 DevTools Protocol 的Network.Response负载对应 CDP 的Network.responseReceived事件并从中取出连接元数据this.#remoteAddress { ip: responsePayload.remoteIPAddress, port: responsePayload.remotePort, };remoteIPAddress与remotePort是 CDPNetwork.Response结构体中的字段由浏览器网络栈在收到响应时填充。remoteAddress()的 getter 只是直接返回这个缓存的快照override remoteAddress(): RemoteAddress { return this.#remoteAddress; }也就是说该地址在构造响应对象那一刻就已固定之后不会随连接状态变化而更新属于一次性快照数据。这一点与securityDetails()返回 TLS/HTTPS 安全连接详情见 puppeteer.httpresponse.securitydetails.md互补前者回答连到哪台服务器后者回答连接是否加密、证书归属。在 packages/puppeteer-core/src/cdp/NetworkManager.ts 附近可以找到CdpHTTPResponse被组装的位置它接收来自 CDP 事件流的响应负载与 extraInfo 事件单测 packages/puppeteer-core/src/cdp/HTTPResponse.test.ts 中构造CdpHTTPResponse时亦使用remoteIPAddress: 127.0.0.1、remotePort: 80这类负载字段印证了数据源结构。四、WebDriver BiDi 实现协议缺口的占位值Firefox 及使用 WebDriver BiDi 协议连接的浏览器走BidiHTTPResponse实现文件位于 packages/puppeteer-core/src/bidi/HTTPResponse.ts。由于 WebDriver BiDi 标准目前没有提供远端地址的等价字段该实现对remoteAddress()返回固定的占位值invokeAtMostOnceForArguments override remoteAddress(): RemoteAddress { return { ip: , port: -1, }; }这里有两个值得注意的细节占位值约定ip为空字符串、port为-1语义上即未知/不可用。跨浏览器编写代码时应通过判断port -1 || !ip来识别 BiDi 场景下的无效数据而不是直接信任返回值。协议差距在测试中被固化仓库的 test/TestExpectations.json 中明确登记了一条针对webDriverBiDi参数组合的期望{ testIdPattern: [network.test] network Response.remoteAddress *, platforms: [darwin, linux, win32], parameters: [webDriverBiDi], expectations: [FAIL], comment: Bidi does not have equivalent field }注释直接写明Bidi does not have equivalent field——即该用例在 BiDi 模式下被标记为预期失败FAIL这正是协议能力差异在官方测试矩阵中的显式表达。因此若你的自动化脚本需要强依赖远端地址信息例如做安全审计、代理校验、合规取证当前应优先使用 Chrome/Chromium CDP 的组合如需覆盖 Firefox则应把该能力视作尽力而为。五、真实调用链与测试用例佐证官方集成测试位于 test/src/network.test.ts 的Response.remoteAddress分组两个用例直接验证了上文描述的语义用例一基础取值should workconst response (await page.goto(server.EMPTY_PAGE))!; const remoteAddress response.remoteAddress(); // Either IPv6 or IPv4, depending on environment. expect( remoteAddress.ip!.includes(::1) || remoteAddress.ip 127.0.0.1, ).toBe(true); expect(remoteAddress.port).toBe(server.PORT);测试注释揭示了关键约束返回的 IP 格式取决于环境——在启用 IPv6 回环的环境下为::1否则为 IPv4 的127.0.0.1而端口必须精确等于本地测试服务器的监听端口。这提醒我们在断言远端地址时不要硬编码某一种 IP 字面量而应允许 IPv4/IPv6 两种形态判断时可以用includes/正则等宽松方式。用例二重定向场景should support redirectsserver.setRedirect(/foo.html, /empty.html); const response (await page.goto(FOO_URL))!; const redirectChain response.request().redirectChain(); expect(redirectChain).toHaveLength(1); expect(redirectChain[0]!.response()!.remoteAddress().port).toBe(server.PORT);该用例表明重定向链上每一跳的中间响应都各自持有独立的HTTPResponse通过request().redirectChain()获取并且每一跳都可以单独调用remoteAddress()查询其远端地址。六、实战连接审计与边界防护场景一监测页面实际连接了哪些主机下面把监听、导航与地址提取组合起来实现一个连接目的地审计器可用于发现页面是否偷偷连向了预期之外的服务器import puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); const destinations new Mapstring, string(); page.on(response, response { const {ip, port} response.remoteAddress(); if (ip) { // 同一 URL 可能命中缓存/多次请求用 URL 作为键覆盖记录 destinations.set(response.url(), ${ip}:${port}); } }); await page.goto(https://example.com, {waitUntil: networkidle0}); for (const [url, addr] of destinations) { console.log(${url} - ${addr}); } await browser.close();场景二识别来自代理的真实对端remoteAddress()反映的是 TCP 连接的真实对端。若 Chrome 通过--proxy-server走代理访问目标站返回的ip:port通常是代理服务器而非目标站地址对比 URL 主机名与返回 IP 是否一致即可判断流量是否经过代理转发。场景三区分缓存命中与网络请求HTTPResponse还提供了fromCache()是否来自浏览器磁盘/内存缓存与fromServiceWorker()是否由 Service Worker 响应等方法。将remoteAddress()与这两者结合可以判断凡是真正走了网络连接的响应才具备有意义的远端地址而缓存或 Service Worker 直接返回的响应其连接元数据往往不完整或已无实际意义解读时应降低对remoteAddress()的权重。场景四跨浏览器适配写法由于 BiDi 返回{ip: , port: -1}推荐封装一个统一访问函数function describeRemoteAddress(remoteAddress: {ip?: string; port?: number}) { if (!remoteAddress.ip || remoteAddress.port -1) { return unavailable (protocol does not expose remote address); } return ${remoteAddress.ip}:${remoteAddress.port}; }七、易混淆点与边界小结与 DNS 结果的差别remoteAddress()返回连接对端地址若启用代理或负载均衡可能与 URL 域名直接解析出的 IP 不一致这是正常现象。IPv4 / IPv6 形态差异同一站点在不同网络环境下可能返回1.2.3.4或[::1]等不同格式断言与日志输出需兼容。重定向链逐跳可取每一跳都有独立的HTTPResponse可借助request().redirectChain()分别读取见上文测试用例二。跨协议可用性不同CDP 提供真实地址WebDriver BiDi 返回占位值ip: 、port: -1且官方测试矩阵中该能力在 BiDi 参数下被标记为预期失败。与securityDetails()互补需要 TLS 证书信息签发者、有效期、SAN 等时调用securityDetails()HTTP 明文场景下该方法返回null。总结HTTPResponse.remoteAddress()是一把轻量但信息量很大的连接探针在 CDP 路径下它基于Network.Response的remoteIPAddress/remotePort字段返回 TCP 连接真实对端在 WebDriver BiDi 路径下受协议限制仅返回占位值。理解其数据来源与协议差异后你可以将它用于请求来源审计、代理行为验证、缓存判定辅助以及重定向链分析与HTTPResponse家族的url()、headers()、securityDetails()、fromCache()等方法配合即可构建完整的响应级网络观测视图。如需查看更多相关 API 定义可继续阅读 HTTPResponse 类总览 与 RemoteAddress 接口。【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/8 23:30:45

STM32F407VET6为何仍是主流?从选型到以太网应用实战解析

STM32F407VET6这颗料,放在2024年怎么看都不算年轻了——2011年发布,Cortex-M4内核,主频168MHz,工艺还是老的90nm级别。但你要是打开电商平台搜一搜,或者去GitHub上翻开源项目,会发现这颗芯片的出镜率高得离…

2026/9/8 23:30:45

nRF52840 USB Dongle开发实战:从环境搭建到烧录调试全解析

简介:nRF52840 MDK USB Dongle 是一套采用 USB Dongle 规格的低成本 nRF52840 微型开发套件,面向物联网、低功耗蓝牙、Thread 等无线协议开发者,适合快速原型验证、多协议节点测试或 PC 端网络协处理器应用。板载 Nordic nRF52840 多协议 SoC…

2026/9/8 23:30:45

PLC现场故障排查:从LINK-100报警看物理层、协议层与逻辑层协同诊断

1. “PLC见闻”不是游记,是工程师在现场踩出来的认知地图很多人第一次看到“有关PLC见闻”这个标题,下意识会以为是某位老师傅写的回忆录,或者学生实习日记——毕竟“见闻”这个词太生活化了,不像技术文档该有的语气。但在我干了1…

2026/9/9 1:56:01

STM32驱动AD9850信号发生器:从原理到扫频实现的完整指南

简介:面向嵌入式开发者的正点原子STM32精英板与AD9850 DDS波形发生器完整工程资源,适合需要实现任意波形输出、学习STM32驱动DDS的电子工程师、学生及爱好者,也适用于信号处理、通信系统实验等教学场景。压缩包共200个文件,大小5.…

2026/9/9 1:56:01

opencode 完全指南:终端AI编程助手的安装、模型配置与实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/9 1:56:01

AI软件怎么选?从三层结构与五种类型,避开冷门工具的坑

刷到那种“冷门AI软件推荐合集”的时候,你是不是也忍不住点收藏?我存过不下二十份,真正打开用超过一周的,可能只有三四个。这不是说那些软件不行,而是我一开始就搞错了顺序——我以为要找到“更厉害的模型”&#xff0…

2026/9/9 1:56:01

服务器ECC内存告警深度解析:从uncorr. ECC到故障排查与选型

1. 凌晨两点半的告警:当服务器报出"uncorr. ECC"时发生了什么1.1 那条告警到底在说什么我记忆很清楚,第一次被内存告警炸醒是凌晨两点多,值班手机连着震了好几下,同一台数据库服务器通过BMC管理界面发来异常通知。远程打…

2026/9/9 1:51:00

量级思维:从日志格式化到容量规划的系统排障实践

做系统排障和容量规划这些年,我越来越确定一件事:真正让系统翻车的,往往不是参数差了几个百分点,而是量级——magnitude——整体差了一个数量级。比如接口耗时从 0.05ms 涨到 50ms,很多人觉得只是"快了慢了"…

2026/9/8 7:15:10

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/8 7:15:10

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/9 0:00:48

MHS模型硬件标准:让大模型像调用软件一样控制物理设备

让Claude真正看着显微镜说“这个细胞形态不太对”,或者让大模型自己调一版机械臂的运动轨迹,这事儿听上去已经很接近科幻片了。但你真上手试一次就会发现,模型不缺智商,缺的是一个能插进显微镜、机械臂、激光控制器里的“通用插座…

2026/9/9 0:00:48

AI五大核心方向详解:从机器学习到大模型,零基础转行选哪条?

会有人告诉我,他想转行学AI,但打开招聘网站一看直接傻眼:机器学习、深度学习、自然语言处理、计算机视觉、大模型应用……满屏都是这些词,好像每个都会一点,又好像每个都离自己很远。还有人上来就问“学Python还是学Ja…

2026/9/9 0:00:49

从50行最小循环到生产级AI引擎:工程化改造全解析

直接说干货。这一章我写的不是那种"hello world跑通某个模型"的教程,而是把AI引擎当做一个真正要上线、要被人调用、要扛流量的系统来聊。从最初只有50行的最小循环,到能够承载生产流量的AI引擎,中间差的不是代码量,而是…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/7 22:45:59

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码