我的JavaScript异常监控策略:保护前端应用免受错误的困扰!

news2024/11/14 20:42:12

在上一篇文章如何及时发现网页的隐形错误中我们讲了,前端有哪些常见的异常,以及如今监控获取这些异常的方法,今天我们就来讲讲我是如何来监控我的JavaScript异常的。

背景

浏览器侧的异常分为两种类型

  • JavaScript 错误,一般来自代码。
  • 静态资源错误,他们可能来自:
    • 通过 XMLHttpRequest、Fetch() 的方式来请求的 http 资源。
    • 利用 <img> 、<script>、<video>、<audio>、<iframe> 等标签加载的资源。
    • 通过创建实例的方式,例如 new Image() 等代码来实现初始化。

既然如此,那就先从JavaScript异常下手

如何做好 JS 异常监控

我们都知道获取异常信息的常见几种方式是

  • window.onerror = cb (DOM0)
  • window.addEventListener(‘error’, cb, true)
  • try-catch (ES提供基本的错误捕获语法)
  • Vue.errorHandler()

我在这里选择选择的是使用JavaScript的window.addEventListener()监听errorunhandledrejection

原因

  • try-catch 。这种异常一般无法直接捕获,因为写了 try-catch 说明开发者已经意识到并做了处理,当然开发者也可以通过自定义上报机制来额外地处理之。
  • 没有被 catch 的 Error。可以通过监听 error 事件捕获。
  • 当 Promise 被 reject 且没有 reject 处理器的时候触发的 PromiseRejection,监听 unhandledrejection 即可。
  • 语法错误,一般语法异常在开发、构建阶段就能发现,这类异常出现程序本身就无法正常运行。不过有特殊情况:eval 中的语法错误是可以捕获的。
  • window.addEventListener(error和unhandledrejection)可以捕获全局范围内发生的未处理异常,无论是同步还是异步代码而且错误信息足够详细并且处理起来方便。

代码演示:
jcode

具体代码:

// 导出一个函数,用于创建 JS 错误监视器
export function createJsErrorMonitor(options: JsErrorMonitorOptions) {


  function getBrowserWindow() {
    return window;
  }
    // 获取浏览器窗口
    const window = getBrowserWindow();
  
  // 如果没有windown,则返回
  if (!window) {
    return;
  }

  // 定义处理错误和拒绝的函数
  const handleError = (e: ErrorEvent) => {
    // 调用 onReport 函数,报告 JS 错误
    options.onReport({
      eventType: EventType.JS_ERROR,
      data: formatError(e),
    });
  };

  const handleRejection = (e: PromiseRejectionEvent) => {
    // 调用 onReport 函数,报告 JS 错误
    options.onReport({
      eventType: EventType.JS_ERROR,
      data: formatError(e),
    });
  };

  // 定义销毁监听器的函数
  const destroyListeners = () => {
    // 移除 error 事件监听器
    window.removeEventListener('error', handleError);
    // 移除 unhandledrejection 事件监听器
    window.removeEventListener('unhandledrejection', handleRejection);
  };

  // 捕获异步 error
  // 添加 error 事件监听器
  window.addEventListener('error', handleError);
  // 添加 unhandledrejection 事件监听器
  window.addEventListener('unhandledrejection', handleRejection);

  // 返回销毁监听器的函数
  return {
    destroy: destroyListeners,
  };
}

但是我们需要注意的是,我们的代码在处理跨域脚本时,还存在一些问题

假设我们要对一段浏览器跨域请求的代码进行监控效果会是怎么样呢?

示例:


    <!-- 监控脚本 -->
    <script src="监控代码"></script>

    <script>
        // 创建 JavaScript 错误监控
        Monitor.createJsErrorMonitor({
            onReport: (e) => {
                console.log(e);
            }
        });
    </script>

    <!-- 示例脚本,模拟跨域错误 -->
   <script src="https://example.com/another-nonexistent.js"></script>

    <!-- 带 crossorigin 属性的示例脚本 -->
    <script src="https://example.com/another-nonexistent.j" crossorigin="anonymous"></script>

结果是代码会出现异常无法捕捉的情况
image.png
我们的第一个 script 的异常没有被监控程序捕获,但是第二个却可以。你可能会问这是为什么呢?

这是因为浏览器跨域规则的限制,在这种情况下捕获到的 ErrorEvent 没有任何有价值的信息。(只能拿到一个模糊的 Script Error 0)。

但是解决方案很简单,我们只需要将相应的 script 标签增加一条 crossorigin=“anonymous” 属性即可

<script src="xxxxx.js" crossorigin="anonymous"></script>

而在真实的 webpack 工程化环境中,我们不应该也不可能去一一的手动修改它们,而是会通过编写一个 webpack 插件,hook 到 html-webpack-pluginalterAssetTagGroups 生命周期钩子上为标签增加属性,

代码如下:

import webpack from 'webpack';
import { Hooks } from 'html-webpack-plugin';

export class AddAnonymousWebpackPlugin {
  apply(compiler: webpack.Compiler) {
    compiler.hooks.compilation.tap('AddAnonymousWebpackPlugin', (compilation) => {
      // 通过最终的 webpack 配置的 plugins 属性,根据插件的 constructor.name 拿到 html-webpack-plugin 实例
     const HtmlWebpackPluginInstance: any = compiler.options.plugins
       // 获取插件构造函数
       .map(({ constructor }) => constructor)
        // 查找HtmlWebpackPlugin构造函数
        .find(constructor => constructor && constructor.name === 'HtmlWebpackPlugin');

      if (HtmlWebpackPluginInstance) {
        // 获取 html-webpack-plugin 所有的 hooks
        const hooks = HtmlWebpackPluginInstance.getHooks(compilation) as Hooks;

        // 在插入标签之前做些什么
        hooks.alterAssetTagGroups.tap(
          'AddAnonymousWebpackPlugin', (data) => {
            // 拿到所有的标签,如果是 script 标签,并且满足我们的匹配函数,则将其 attributes.crossorigin = "anonymous"
          data.headTags.forEach(tag => {
              if (tag.tagName === 'script') {
                // 为script标签添加crossorigin属性
                tag.attributes.crossorigin = "anonymous";
              }
            });
            return data;
          },
        );
      }
    });
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1996528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么在网页编辑文字时键盘输入换行要停顿一下 网页才显示

事情的起因&#xff1a; 不知道从什么时候开始&#xff0c;在浏览器上编辑文字时&#xff0c;换行操作总是延迟响应&#xff0c;但点击空格网页响应速度正常。时间长了也习惯了&#xff0c;可能觉得本来就是这样吧&#xff0c;网页编辑可能不稳定&#xff0c;加上自己使用的是蓝…

结构体structure、共用体union

结构体 结构体类型——用来描述复杂数据的一种数据类型 构造类型&#xff08;用户自定义类型&#xff09; struct 结构体类型名 { 成员列表; }; struct关键字&#xff1a;表明是在构造一个结构体的类型 结构体名&#xff1a;用来描述结构体这个类型的一个名称 成员列表&…

JavaWeb系列十一: Web 开发会话技术Session

Web 开发会话技术Session Session有什么用session基本原理session原理示意图session可以做什么如何理解Session Session常用方法Session底层实现机制原理分析图应用实例session实现原理动画 Session生命周期Session生命周期说明Session生命周期实例 作业布置 Session有什么用 …

8.9 C++

1.思维导图 2. 搭建一个货币的场景&#xff0c;创建一个名为 RMB 的类&#xff0c;该类具有整型私有成员变量 yuan&#xff08;元&#xff09;、jiao&#xff08;角&#xff09;和 fen&#xff08;分&#xff09;&#xff0c;并且具有以下功能&#xff1a; (1)重载算术运算符…

书生大模型实战营第三期_L2-LMDeploy 量化部署进阶实践(81班1101作业)

大模型的痛点 大模型的计算量是非常大的 2. 显存的相应区域是非常大的 3.访存瓶颈 GPU的大部分时间都花在数据交换上面不断拉高batchsize&#xff0c;不断地提高计算的访存比是不是会有较好的效果呢&#xff1f;这是一个很好的想法&#xff0c;但是显存不够就会很尴尬为了能…

【youcans动手学模型】YOLO5 实战(中)训练目标检测模型

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans YOLO5 实战 &#xff08;上&#xff09;环境配置与测试 【youcans动手学模型】YOLO5 实战&#xff08;中&#xff09;使用自己的数据集训练目标检测模型 1. 准备训练数据集1.1 开源数据集1.2 YOLOv5 …

k8s1.18.0完整部署教程

k8s的官网地址&#xff1a;https://kubernetes.io/docs Kubernetes 也称为 K8s&#xff0c;是一个开源系统&#xff0c;用于自动化容器化应用程序的部署、扩展和管理。 K8s通过各种资源对象来管理pod相关的功能&#xff0c;借助pod本身的功能实现大规模容器应用的自动化管理&…

享界S9+问界M9,华为智选车的高端局

作者 |老缅 编辑 |德新 8月6日&#xff0c;鸿蒙智行在北京发布D级纯电旗舰轿车&#xff0c;也是北汽 - 华为智选车合作的第一款车型&#xff0c;享界S9。 享界S9搭载了包括华为乾崑ADS 3.0在内的多项首发技术&#xff0c;全系标配100kWh华为800V巨鲸电池。 而在价格上&#…

mysql⑥:约束

一&#xff0c;概念 例子&#xff1a; 外键约束 例子&#xff1a; 外键的删除和更新

从商业角度分析,充电桩还能赚钱吗?

一、投入与产出 1、投入 是建设成本&#xff0c;包括设备&#xff08;箱变、充电设备、电缆等&#xff09;、土建和配套&#xff08;雨棚、照明、监控等&#xff09;。二是运营成本&#xff0c;包括租金、人工、电损等。 2、产出 充电手续费以及增值服务&#xff08;停车费…

力扣高频SQL 50题(基础版)第三十八题之1484.按日期分组销售产品

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第三十八题1484.按日期分组销售产品题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题&#xff08;基础版&#xff09;第三十八题 1484.按日期分组销售产品 题目说明 表 Activities&#xff1a; ---…

shell的条件测试

为了能够正确处理Shell程序运行过程中遇到的各种情况&#xff0c;Linux Shell提供了一组测试运算符。 通过这些运算符&#xff0c;Shell程序能够判断某种或者几个条件是否成立。 条件测试在各种流程控制语句&#xff0c;例如判断语句和循环语句中发挥了重要的作用&#xff0c;所…

算法训练.

一.扩散 题解&#xff1a; 计算点之间的距离&#xff0c;然后对图进行处理即可&#xff0c;这个数据规模较小&#xff0c;因此我使用了floyd,还有最小生成树和二份答案加并查集的写法&#xff1b; 代码&#xff1a; #include <iostream> #include <cstring> #in…

微信小程序流量主收益

小程序流量主已经开通三天了,目前收益1.42,,,,,,,,,,,,,,,不过确实点击量不怎么多 再附上我的流量主小程序 点击量如果上去的话,收益应该还是可观的,有想开流量主的任何问题都可以骚扰我,,对小程序有任何意见也欢迎反馈~ 一起进步,一起学习~

CentOS linux 安装openssl(openssl拒绝服务漏洞【CVE-2022-0778】解决)

一、安装 1.下载相关openssl包 下载地址&#xff1a; https://www.openssl.org/source/ 2.将下载好的压缩包放到 /app/server/nginx 路径下&#xff08;根据自己实际需求定义&#xff09; 3.切换至该路径 cd /app/server/nginx4.压缩包解压 压缩包解压 &#xff1a;tar -…

矩阵算法的介绍和实现

一. 介绍 首先我们要清楚矩阵是什么&#xff1a;矩阵是一个按照长方阵列排列的复数或实数集合 1> 定义 定义&#xff1a;mn矩阵为mn个数排成的m行n列的表格&#xff0c;当mn时&#xff0c;矩阵A称为n阶方阵或者n阶矩阵。零矩阵&#xff1a;矩阵所有元素都为0。同型矩阵&a…

Centos7.6配置阿里云镜像源

1、备份本地镜像源&#xff0c;将/etc/yum.repos.d/下所有文件备份到/etc/yum.repos.d/bak/下 2、下载阿里云镜像 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo 3、清除yum缓存-yum clean all 4、验证镜像源仓库 yum repolist

Redis漏洞复现【vulhub靶场】

步骤一&#xff1a;打开靶场 进入目录:cd /vulhub-master/redis/4-unacc 启动:docker-compose up -d 检查:docker-compose ps 步骤二&#xff1a;打开kali在kali安装redis程序 #安装redis apt-get install redis #redis链接 redis-cli -h 192.168.4.176-p 6379#redis常见命令 (…

智慧合规与合同管理是未来企业竞争力的关键

在法律和市场规则日益完善的当代&#xff0c;企业合规是公司治理的核心。它像是一道紧箍咒&#xff0c;确保企业遵循法律法规&#xff0c;避开违规风险&#xff1b;同时也是一枚护身符&#xff0c;保护企业免受不必要的诉讼和罚款&#xff1b;更加是企业竞争力的体现&#xff0…

使用 Prometheus 和 Grafana 监控 FastAPI 服务

在现代应用开发中&#xff0c;监控和可视化服务的运行状态和性能指标对于保证系统稳定性至关重要。本文将介绍如何使用 Prometheus 和 Grafana 对 FastAPI 服务进行监控和可视化&#xff0c;并展示如何通过 prometheus_fastapi_instrumentator 将 FastAPI 应用与 Prometheus 集…