# 异常类型
# JS 代码执行异常
举个例子
1 2
| var a = {}; a.b.c = 123;
|
针对 JS 代码执行异常我们可以 try...catch
包裹代码块,或者采用 window.addEventListener('error', listener)
来进行捕获
# Promise reject 异常
这类异常通常出现 promise 出现 reject 但是未被 catch 的情况
针对这类异常通常采用 window.addEventListener('unhandledrejection', listener)
来进行捕获
# 资源加载异常
这类异常出现在我们请求的 js css img 等链接资源失效的时候,这类异常并不会冒泡,所以需要在捕获阶段进行处理, window.addEventListener('error', listener, true)
第三个参数表示在捕获阶段进行处理
# 接口请求异常
- fetch 请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| fetchReplacer(originalFetch: typeof fetch) { return function (...args: Parameters<typeof fetch>) { return originalFetch(...args) .then(res => { if (!res.ok) { // TODO 错误处理 } return res; }) .catch(error => { // TODO 错误处理 throw error; }); }; }
const originalFetch = window.fetch; if (!originalFetch) { console.warn('fetch is not supported'); return; } window.fetch = fetchReplacer(originalFetch);
|
- xhr 请求
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
| replacer(originalXHR: typeof XMLHttpRequest) { const originalSend = originalXHR.prototype.send; const originalOpen = originalXHR.prototype.open; const shouldSkipHandler = (e: ProgressEvent<XMLHttpRequestEventTarget>) => { const status = (e.target as XMLHttpRequest & ExtraXMLHttpRequest).status; const type = e.type; // 正常情况 + 超时情况/错误情况 触发的loadend return (type === 'loadend' && status === 0) || (status + '').startsWith('2'); }; // 重写open方法 方便错误处理阶段获取接口请求信息 originalXHR.prototype.open = function open( this: XMLHttpRequest & ExtraXMLHttpRequest, method: string, url: string | URL, async: boolean = true, username?: string | null, password?: string | null ) { this.method = method; this.requestURL = typeof url === 'string' ? url : url.toString(); return originalOpen.apply(this, [method, url, async, username, password]); }; originalXHR.prototype.send = function send( this: XMLHttpRequest & ExtraXMLHttpRequest, ...args: Parameters<typeof originalSend> ) { const handler = function (e: ProgressEvent<XMLHttpRequestEventTarget>) { // 获取请求URL 请求状态 请求方法 const { responseURL, requestURL, status, statusText, method, responseText } = e.target as XMLHttpRequest & ExtraXMLHttpRequest; if (shouldSkipHandler(e)) return; // TODO 错误处理 }; // 监听错误 (网络中断 / 跨域等) this.addEventListener('error', handler); // 监听请求错误 (请求体的内容非2xx) this.addEventListener('loadend', handler); // 监听请求超时 this.addEventListener('timeout', handler); return originalSend.apply(this, args); }; }
const originalXHR = window.XMLHttpRequest; if (!originalXHR) { console.warn('XMLHttpRequest is not supported'); return; } replacer(originalXHR);
|
# 跨域脚本执行异常
对于跨域的脚本 如果没有添加 crossorigin="anonymous"
则三方脚本的错误只显示 "Script error."
添加了 crossorigin="anonymous"
的脚本,对于 response 需要正确设置 Access-Control-Allow-Origin
允许当前网页进行跨域获取脚本
anonymous
表示:
- 不发送用户凭证(如 cookies)到其他域
- 可以捕获脚本的详细错误信息
- 不使用
anonymous
:
- 跨域脚本错误只显示 “Script error.”
- 无法获取详细错误信息
crossorigin="use-credentials"
- 会发送用户凭证到其他域
- 需要服务器返回
Access-Control-Allow-Credentials: true
1
| <script src="http://www.example.com/app.js" crossorigin="anonymous"></script>
|
# 前端如何做全自动化的异常监控呢