尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Puppeteer ConsoleMessage.location() 详解:用 url、lineNumber、columnNumber 精确定位控制台消息来源

Puppeteer ConsoleMessage.location() 详解:用 url、lineNumber、columnNumber 精确定位控制台消息来源 Puppeteer ConsoleMessage.location() 详解用 url、lineNumber、columnNumber 精确定位控制台消息来源【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer本篇指南围绕 Puppeteer 的ConsoleMessage.location()方法及其返回的ConsoleMessageLocation接口展开说明如何在监听page.on(console)事件时拿到一条控制台消息的来源资源 URL、行号与列号。读完本文你可以理解 location 三个字段的精确含义0-based 行/列、可能为undefined的语义、Puppeteer 内部在 CDP 与 WebDriver BiDi 两种协议下如何填充这些数据以及如何把这一 API 用于错误溯源与自动化日志采集。1. API 概览location() 的签名与返回值location()是 ConsoleMessage 类上的公开方法文档描述为 The location of the console message.控制台消息的位置签名如下class ConsoleMessage { location(): ConsoleMessageLocation; }该方法返回一个 ConsoleMessageLocation 对象对应源码中的同名接口定义在 packages/puppeteer-core/src/common/ConsoleMessage.ts#L15-L30。一个典型的使用场景页面内脚本抛出控制台消息后通过page.on(console)监听并立即读取位置信息无需解析message.text()字符串即可知道消息来自哪个文件、哪一行。2. ConsoleMessageLocation 的三个字段ConsoleMessageLocation是一个完全可选字段的接口三个属性及其官方说明如下源自 docs/api/puppeteer.consolemessagelocation.md属性修饰符类型说明默认值urloptionalstring资源 URLresource未知时为undefined无lineNumberoptionalnumber资源内的0-based行号未知时为undefined无columnNumberoptionalnumber资源内的0-based列号未知时为undefined无三个关键点需要在实战中注意行号与列号都是 0-based。官方源码注释明确写着 0-based line number in the resource if known orundefinedotherwise见 packages/puppeteer-core/src/common/ConsoleMessage.ts#L20-L29。也就是说浏览器 DevTools 里显示为第 9 行的语句lineNumber是8。字段可能缺失。当浏览器无法提供某个维度例如某些网络错误日志只有发起请求的目标 URL、没有脚本位置时对应字段就是undefined而不是0。消费代码必须做判空不能直接拿lineNumber拼链接。url指向的是资源resource即产出该控制台消息的脚本所在文档/模块地址而不是消息内容中提到的其他 URL——这一点后文的 fetch 失败示例会专门说明。3. 实现原理location() 的取值与回退逻辑location()的完整实现只有几行位于 packages/puppeteer-core/src/common/ConsoleMessage.ts#L112-L120/** * The location of the console message. */ location(): ConsoleMessageLocation { return ( this.#stackTraceLocations[0] ?? (this.#frame ? {url: this.#frame.url()} : {}) ); }从源码结构看它的取值策略分两级首选调用栈的第一帧。ConsoleMessage构造时接收一个stackTraceLocations: ConsoleMessageLocation[]参数packages/puppeteer-core/src/common/ConsoleMessage.ts#L61-L89location()返回其中的第一个元素。因为console.log/trace等 API 触发的栈帧顺序是自顶向下的第一帧正是执行console.*调用的那个位置。回退所在 Frame 的 URL。如果栈信息为空#stackTraceLocations[0]为undefined但消息来自某个Frame则退化为{url: frame.url()}只给出文档级位置两者都没有时返回空对象{}。与之配套的stackTrace()方法packages/puppeteer-core/src/common/ConsoleMessage.ts#L122-L127返回完整的栈帧数组因此一个常用技巧是需要精确位置用location()需要排查是谁触发的这条日志时遍历stackTrace()找业务代码所在帧。4. 数据来源CDP 与 BiDi 两条填充链路stackTraceLocations在构造ConsoleMessage时被填充仓库中一共有三条构造路径分别对应 CDP 的 Runtime 域、CDP 的 Log 域和 WebDriver BiDi4.1 CDP Runtime 域console API 调用CDP 的Runtime.consoleAPICalled事件即页面里console.log、console.trace等经由 packages/puppeteer-core/src/cdp/utils.ts#L20-L51 的createConsoleMessage转换为ConsoleMessageexport function createConsoleMessage( event: Protocol.Runtime.ConsoleAPICalledEvent, values: JSHandle[], targetId?: string, ): ConsoleMessage { // ... const stackTraceLocations []; if (event.stackTrace) { for (const callFrame of event.stackTrace.callFrames) { stackTraceLocations.push({ url: callFrame.url, lineNumber: callFrame.lineNumber, columnNumber: callFrame.columnNumber, }); } } return new ConsoleMessage( convertConsoleMessageLevel(event.type), textTokens.join( ), values, stackTraceLocations, undefined, event.stackTrace, targetId, ); }注意这里逐帧映射了 CDPCallFrame的url、lineNumber、columnNumber三个字段。该结果最终由 packages/puppeteer-core/src/cdp/Page.ts#L980 以PageEvent.Console事件发出即用户代码里监听的page.on(console)。4.2 CDP Log 域网络/日志类错误像fetch失败这类浏览器日志并非console.*调用而是走Log.entryAdded。对应处理逻辑在 packages/puppeteer-core/src/cdp/Page.ts#L573-L595#onLogEntryAdded(event: Protocol.Log.EntryAddedEvent): void { const {level, text, args, source, url, lineNumber, stackTrace} event.entry; // ... if (source ! worker) { this.emit( PageEvent.Console, new ConsoleMessage( convertConsoleMessageLevel(level), text, [], [{url, lineNumber}], undefined, stackTrace, this.#primaryTarget._targetId, ), ); } }从源码结构看Log 域构造的位置信息只包含url和lineNumber没有columnNumber——这正是测试中该场景断言columnNumber为undefined的原因。4.3 WebDriver BiDi在 BiDi 模式下位置数据由 packages/puppeteer-core/src/bidi/util.ts#L44-L58 的getStackTraceLocations从Bidi.Script.StackTrace.callFrames映射而来字段名与 CDP 保持一致最终经getConsoleMessage同文件 L63-L88构造ConsoleMessage。两条协议链路的映射逻辑完全同构因此上层 API 的行为在 Chrome/Firefox 间是可预期的。5. 测试用例验证的三种典型行为仓库测试 test/src/console.test.ts 对location()的返回值做了精确断言是理解该 API 行为边界最可靠的参照5.1 网络错误日志只有 urlshould have location when fetch fails用例test/src/console.test.ts#L246-L266在页面中执行fetch(http://wat)断言expect(message.location()).toEqual({ url: http://wat/, lineNumber: undefined, });这里url是发起请求的目标地址由 Log 域的url字段透传lineNumber为undefined。它对应 4.2 节中 Log 域的填充路径说明对 Log 类消息不要假设行号一定存在。5.2 console API 调用url 0-based 行列should have location and stack trace for console API calls用例test/src/console.test.ts#L267-L290加载了 test/assets/consoletrace.html 页面断言expect(message.text()).toBe(yellow); expect(message.type()).toBe(trace); expect(message.location()).toEqual({ url: server.PREFIX /consoletrace.html, lineNumber: 8, columnNumber: 16, }); expect(message.stackTrace()).toEqual([ { url: server.PREFIX /consoletrace.html, lineNumber: 8, columnNumber: 16, }, // ... 后续帧 ]);两个要点被验证location()与stackTrace()的第一帧一致即 3 节的取栈首帧策略lineNumber: 8是 0-based 计数对应页面上console.trace(yellow)的源行。5.3 Worker 中的 console 消息Worker 里产生的控制台消息会被转发到页面事件上packages/puppeteer-core/src/cdp/Page.ts#L384-L404 会把WebWorker的Console事件 re-emit 为PageEvent.Console当页面侧没有监听者时还会自动dispose()消息参数以释放对象。test/src/worker.test.ts#L75 对 Worker 场景下的message.location()同样做了断言证明 Worker 消息一样携带位置信息。6. 实战模式错误溯源与日志采集结合上述机制以下是可直接使用的监听模板import puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); page.on(console, msg { const loc msg.location(); // 字段可能为 undefined需判空 const where loc.url ?? unknown; const line loc.lineNumber ! undefined ? loc.lineNumber 1 : ?; console.log([${msg.type()}] ${msg.text()} ${where}:${line}); // 需要追踪触发链时遍历完整栈 for (const frame of msg.stackTrace()) { console.log( - ${frame.url}:${(frame.lineNumber ?? 0) 1}); } }); await page.setContent( scriptconsole.error(boom);/script ); await browser.close();使用建议行号 1 再展示内部 0-based展示给用户时通常转 1-based如 5.2 中lineNumber: 8对应源码第 9 行。按type()分流ConsoleMessageType共 19 种取值log、error、trace、assert、startGroup等完整枚举见 packages/puppeteer-core/src/common/ConsoleMessage.ts#L36-L55采集器可据此过滤或分级。Log 类消息只有 url网络失败等非脚本类日志按 4.2 的路径填充columnNumber恒为undefined断言和展示逻辑都应兼容。location()与stackTrace()的分工前者给消息在哪后者给消息由谁触发排查深层调用时以后者为准。7. 相关文档与源码索引内容路径location()方法文档docs/api/puppeteer.consolemessage.location.mdConsoleMessageLocation接口文档docs/api/puppeteer.consolemessagelocation.mdConsoleMessage类文档docs/api/puppeteer.consolemessage.md接口与类实现packages/puppeteer-core/src/common/ConsoleMessage.tsCDP Runtime 域转换packages/puppeteer-core/src/cdp/utils.tsCDP Log 域事件处理packages/puppeteer-core/src/cdp/Page.tsBiDi 栈帧映射packages/puppeteer-core/src/bidi/util.ts行为验证测试test/src/console.test.ts、test/src/worker.test.tsConsoleMessage.location()是 Puppeteer 控制台事件体系中定位信息的入口它以栈首帧优先、Frame URL 兜底的两级策略把 CDPCallFrame与 BiDicallFrames中的url/lineNumber/columnNumber统一抽象为一个可判空消费的ConsoleMessageLocation是编写错误采集、日志落盘与测试断言逻辑时应当优先使用的 API。【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表