如何监控浏览器crash?

📌 前言

页面崩溃是影响用户体验的最严重事故 ------页面完全失效,代码停止执行,即使等待也无法自行恢复,甚至常规的错误监控也会随之失效。

崩溃 vs 卡顿:卡顿是"暂时响应慢",崩溃是"彻底无法用"。崩溃发生后,页面上报能力归零,必须依赖浏览器机制。


🎯 方案选型对比

方案 实现原理 ✅ 优势 ❌ 劣势 可靠性
本地状态存储 崩溃前标记状态,二次进入上报 实现简单 依赖用户二次进入,4数据滞后,wu bao ⭐⭐
Service Worker 心跳 SW 独立生命周期,跨页面检测 独立于页面,存活时间长 ;兼容性较reporting api高一点 误报率高(卡顿误判为崩溃) ;开发量大 ⭐⭐⭐
Reporting API 🏆 浏览器原生崩溃报告机制 页面崩溃后仍可上报,无需业务代码干预 兼容性要求高 ⭐⭐⭐⭐⭐

核心结论Reporting API 是当前唯一能在页面彻底崩溃后仍可靠上报的技术方案

reporting api 详解

1. 工作原理

浏览器通过 Reporting-Endpoints 响应头 声明崩溃报告接收地址。当页面发生崩溃时,浏览器在后台独立线程完成上报,页面主线程的终止不影响报告发送。

ReportingObserverdeveloper.chrome.com/blog/report... 适合开发者在前端主动监听和处理报告 (只支持获取 deprecation || intervention2种报告)

Reporting-Endpoints 如果希望浏览器自动上报崩溃等异常,需要通过 Reporting-Endpoints 响应头声明上报端点。 这种方式下,前端业务代码无需改动,只需配置响应头即可。

2. Reporting-Endpoints 上报字段分析

字段 说明
age 报告的时间戳与当前时间之间的毫秒数。
body 实际报告数据 ,已序列化为 JSON 字符串。报告的 body 中包含的字段由报告的 type 决定。 ⚠️ 注意 :不同类型的报告,其 body 结构不同。下面为 type = crashbody 包含的字段详解: 1.body.crash_report_api 可存放额外信息,读取自 window.crashReport 中的值。 2.body.reason 崩溃原因,取值包括: - oom:页面内存溢出 - unresponsive:页面长时间无响应,被浏览器强制终止 3.body.stack 崩溃时的 JavaScript 调用堆栈。body.reasonunresponsive且响应头需包含:document-policy = include-js-call-stacks-in-crash-reports(Chrome 137+ 开始支持) 该字段可从崩溃的文档中恢复调用堆栈。 3.body.is_top_level 崩溃页面是否属于顶级可遍历对象(top-level traversable)。 4.body.visibility_state 崩溃时页面的可见性状态,取值 visiblehidden
type 报告类型,例如 csp-violationcoep 等。 🎯 需要关注的是crash 类型。
url 崩溃发生的页面地址。
user_agent 生成报告时所使用的请求的 User-Agent 标头。

window.crashReport

window.crashReport的使用方法(可以携带一些额外的信息,便于后续分析),但需要注意的是,该api还在实验阶段,需要浏览器开启配置项后,才可以使用

github.com/WICG/crash-...

dart 复制代码
await window.crashReport.initialize('crash-report');   // 初始化
// 设置基础信息
window.crashReport.set('pageUrl', window.location.href) // set信息
window.crashReport.set('pageTitle', document.title)
//移除信息
window.crashReport.remove('pageTitle', document.title)

实现示例

在服务端配置Reporting-Endpoints头,default中是接受报告的服务器地址。由于window.crashReport还是实验api,那么如果一定需要传递额外信息,则可以给url上增加query来实现

less 复制代码
app.use('/', express.static(path.join(__dirname, './public'), {
  setHeaders: (res) => {
    res.setHeader('Reporting-Endpoints', 'default="https://crash-report.free.beeceptor.com"');
  }
}));
结果展示

内存暴涨导致的crash

json 复制代码
[  
    {  
        "age": 10,  
        "body": {  
            "crash_report_api": {  
                "cookieEnabled": "true",  
                "crashTime": "2025-12-30T09:05:53.703Z",  
                "crashType": "oom",  
                "language": "en",  
                "memory": "[object Object]",  
                "pageLoadTime": "2025-12-30T09:05:48.822Z",  
                "pageTitle": "页面崩溃模拟 Demo",  
                "pageUrl": "<https://localhost:5000/crash.html>",  
                "platform": "MacIntel",  
                "referrer": "direct",  
                "screenColorDepth": "24",  
                "screenHeight": "1080",  
                "screenWidth": "1920",  
                "sessionId": "1767085548824-v4mushd65ib",  
                "timestamp": "1767085548823",  
                "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",  
                "viewportHeight": "958",  
                "viewportWidth": "601"  
            },  
            "is_top_level": true,  
            "visibility_state": "visible"  
        },  
        "type": "crash",  
        "url": "https://localhost:5000/crash.html",  
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"  
    }  
]

报告接收服务搭建

  • 支持跨域
  • 支持解析application/reports+json类型
javascript 复制代码
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use((req, res, next) => {
    // 设置 CORS 响应头
    res.header('Access-Control-Allow-Origin', '*'); // 生产环境建议指定具体域名
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    res.header('Access-Control-Max-Age', '86400'); // 预检请求缓存 24 小时

    // 处理预检请求(OPTIONS)
    if (req.method === 'OPTIONS') {
      return res.sendStatus(200);
    }
    
    next();
  });

  // // 中间件:解析 JSON 请求体
  app.use(bodyParser.json({type: 'application/json'}));
  app.use(bodyParser.json({type: 'application/reports+json'}));

参考资料

1.window.crashReport:github.com/WICG/crash-...

2.zhuanlan.zhihu.com/p/40273861 如何监控网页崩溃

3.developer.chrome.com/docs/capabi...

4.juejin.cn/post/743899...

相关推荐
mCell7 小时前
如何零成本搭建个人站点
前端·程序员·github
mCell8 小时前
为什么 Memo Code 先做 CLI:以及终端输入框到底有多难搞
前端·设计模式·agent
恋猫de小郭8 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
少云清8 小时前
【安全测试】2_客户端脚本安全测试 _XSS和CSRF
前端·xss·csrf
银烛木8 小时前
黑马程序员前端h5+css3
前端·css·css3
m0_607076608 小时前
CSS3 转换,快手前端面试经验,隔壁都馋哭了
前端·面试·css3
听海边涛声9 小时前
CSS3 图片模糊处理
前端·css·css3
IT、木易9 小时前
css3 backdrop-filter 在移动端 Safari 上导致渲染性能急剧下降的优化方案有哪些?
前端·css3·safari
0思必得09 小时前
[Web自动化] Selenium无头模式
前端·爬虫·selenium·自动化·web自动化
anOnion9 小时前
构建无障碍组件之Dialog Pattern
前端·html·交互设计