相关文章
错误监控的手段
一、什么是错误监控
错误监控是指在前端应用中收集、分析和监控 JavaScript 错误、HTTP 错误等错误信息的过程。通过错误监控,可以及时发现并解决前端应用中的错误,提高用户体验和应用稳定性。以下是对错误监控的详细介绍:
二、错误类型
- JavaScript 错误: 包括语法错误、运行时错误和未捕获的异常。例如,代码中的语法错误、变量未定义、空指针异常等。
- HTTP 错误: 发生在网络请求过程中的错误,包括请求超时、404 Not Found、500 Internal Server Error 等。
三、如何捕获
捕获JS语法错误、运行时错误
通过在全局范围内监听 JavaScript 的错误事件,如 window.onerror 和 window.addEventListener(‘error’),可以捕获并处理未被捕获的 JavaScript 错误。这种方法可以用于捕获语法错误、运行时错误等。
window.onerror 和 window.addEventListener(‘error’)区别
捕获的错误类型
- window.onerror 只能捕获全局的未捕获的 JavaScript 错误,包括语法错误、运行时错误和未捕获的异常。
- window.addEventListener(‘error’, listener) 可以捕获更多类型的错误,包括资源加载错误(如图片加载失败、CSS 加载失败等)、跨域脚本错误等。
事件冒泡
- window.onerror 无法阻止错误事件冒泡到浏览器的默认错误处理机制。如果你返回 true(或者一个字符串)来表示你已经处理了错误,错误仍然会冒泡并被浏览器默认的错误处理机制处理。
- window.addEventListener(‘error’, listener) 允许你调用 event.preventDefault() 来阻止错误事件的默认行为。这意味着你可以完全控制错误的处理方式,并且阻止浏览器默认的错误处理机制。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <script> window.addEventListener("error", function (event) { const message = event.message; const source = event.filename; const lineno = event.lineno; const colno = event.colno; const error = event.error;
console.error("【监控】GET Error"); console.error("【监控】Message:", message); console.error("【监控】Source:", source); console.error("【监控】Line:", lineno); console.error("【监控】Column:", colno); console.error("【监控】Error Object:", error); });
function triggerError() { undefinedFunction(); }
triggerError(); </script> </head> <body></body> </html>
|
输出
捕获资源加载错误
由于路径问题、网络问题、服务器问题或资源文件本身问题等原因导致的资源加载失败情况的方法。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <script> window.addEventListener( "error", function (event) { console.error("【监控】GET Error"); console.error("【监控】Type:", event.type); console.error("【监控】Time:", event.timeStamp);
const errorSources = { IMG: "src", SCRIPT: "src", LINK: "href", };
const tagName = event.target.tagName; if (tagName in errorSources) { const sourceAttribute = errorSources[tagName]; const source = event.target[sourceAttribute]; console.error("【监控】Source:", source); console.error(""); } else { console.error("【监控】event:", event); } }, true );
function triggerImgError() { const img = document.createElement("img"); img.src = "path/to/your/image.jpg"; document.body.appendChild(img); } triggerImgError();
function triggerScriptError() { const script = document.createElement("script"); script.src = "path/to/your/script.js"; document.body.appendChild(script); } triggerScriptError();
function triggerStyleError() { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = "path/to/your/styles.css"; document.head.appendChild(link); } triggerStyleError(); </script> </body> </html>
|
输出
捕获 Promise 错误
当一个 Promise 被拒绝(rejected)且没有被捕获时触发。unhandledrejection事件提供了一种机制来捕获在 Promise 链中没有被处理的错误,允许开发者在发生错误时采取适当的措施。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <script> window.addEventListener("unhandledrejection", function (event) { const { promise, reason } = event;
console.error("【监控】GET Error"); console.error("【监控】Type:", event.type); console.error("【监控】Time:", event.timeStamp); console.error("【监控】Promise:", event.promise); console.error("【监控】Reason:", event.reason); });
const rejectedPromise = new Promise((resolve, reject) => { reject(new Error("Unhandled Promise Error")); }); </script> </head> <body></body> </html>
|
输出
捕获网络请求错误
通过监控网络请求,可以捕获到资源加载失败、接口请求错误等情况。可以通过拦截XMLHttpRequest、fetch等方法来实现监控。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <script> var originalOpen = window.XMLHttpRequest.prototype.open; var originalSend = window.XMLHttpRequest.prototype.send;
window.XMLHttpRequest.prototype.open = function(method, url) { this.__url = url; originalOpen.apply(this, arguments); };
window.XMLHttpRequest.prototype.send = function() { var self = this;
this.addEventListener("error", function() { console.error("【监控】 GET Error"); console.error("【监控】URL:", self.__url); console.error("【监控】Status:", self.status); });
originalSend.apply(this, arguments); };
var xhr = new XMLHttpRequest(); xhr.open("GET", "https://example.com/nonexistent", true); xhr.send(); </script> </body> </html>
|
输出
捕获前端框架提供的错误
vue2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <button @click="causeError">Click me to cause error</button> </div> </template>
<script> export default { methods: { causeError() { nonexistentFunction(); } } } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from 'vue' import App from './App.vue'
Vue.config.errorHandler = function (err, vm, info) { console.error('Vue Error:', err); console.error('Vue Component:', vm); console.error('Vue Error Info:', info); };
new Vue({ render: h => h(App), }).$mount('#app')
|
在这个全局配置中,我们将 Vue.config.errorHandler 设置为一个函数,该函数接收三个参数:err 表示错误对象,vm 表示出错的 Vue 实例,info 表示一个 Vue 特定的错误信息,比如在模板渲染期间出错时的错误信息。在错误处理函数中,我们可以对错误进行适当的处理,比如打印错误信息、上报错误到服务器等。
vue3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { createApp } from 'vue'; import App from './App.vue';
const app = createApp(App);
const errorHandler = (error, vm, info) => { console.error('Vue Error:', error); console.error('Vue Component:', vm); console.error('Vue Error Info:', info); };
window.addEventListener('error', errorHandler);
app.mount('#app');
|
react类组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import React, { Component } from 'react';
class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false }; }
componentDidCatch(error, info) { this.setState({ hasError: true }); console.error('Error caught by error boundary:', error); }
render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } }
class MyComponent extends Component { render() { return ( <ErrorBoundary> {} <ChildComponent /> </ErrorBoundary> ); } }
class ChildComponent extends Component { render() { return <button onClick={this.handleClick}>Click me</button>; } }
export default MyComponent;
|
react函数式组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import React, { useEffect } from 'react';
const errorHandler = (error, vm, info) => { console.error('React Error:', error); console.error('React Component:', vm); console.error('React Error Info:', info); };
window.addEventListener('error', errorHandler);
const MyComponent = () => { const causeError = () => { nonexistentFunction(); };
useEffect(() => { return () => { window.removeEventListener('error', errorHandler); }; }, []);
return ( <div> <button onClick={causeError}>Click me to cause error</button> </div> ); };
export default MyComponent;
|
捕获异步错误
在 JavaScript 中,异步的错误是无法直接捕获的,因为它们在异步上下文中执行,而错误会在执行上下文中被捕获并处理。然而,你可以通过一些技巧来间接地捕获 setTimeout 内部的错误。
一种方法是封装 函数,创建一个可以捕获内部错误的函数。例如,你可以创建一个 safeSetTimeout 函数,类似于以下方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function GSetTimeout(callback, delay) { setTimeout(() => { try { callback(); } catch (error) { console.error('An error occurred in setTimeout callback:', error); } }, delay); }
GSetTimeout(() => { }, 1000);
|
捕获跨域错误
JavaScript无法直接捕获跨域错误。浏览器出于安全考虑,限制了跨域请求的能力以及对跨域资源的访问。跨域错误通常是由浏览器的同源策略(Same Origin Policy)所引起的。
如果你试图在JavaScript中发送一个跨域请求,浏览器会阻止该请求,并且不会触发相应的JavaScript错误事件。相反,它会在控制台中显示一条错误消息,提示请求被阻止了,但这个错误是不可捕获的。
捕获内存错误
在前端中,内存错误通常是由于内存泄漏或大量数据处理等原因导致的。由于浏览器环境的限制,我们无法直接监控内存错误。