tsp-component
Version:
提供多端和react版本的UI组件
224 lines (215 loc) • 6.47 kB
text/typescript
/// <reference path="./definition.d.ts" />
import WebApi from '../ajax/webapi';
import { userAgent } from '../util/device';
import { urlStartIndexForString, getCurrentRoute } from '../util/router';
declare const process: {
env: {
NODE_ENV: string;
}
};
class Exception {
/**
* api名称
*/
public static apiname: string = '/api/product/exception/create';
/**
* 产品编码
*/
public static productCode: ExceptionProductCode;
/**
* 经度
*/
public static lat: string;
/**
* 纬度
*/
public static lng: string;
/**
* 账号
*/
public static account: string;
/**
* 微信用户标示
*/
public static openId: string;
/**
* 版本
*/
public static version: string;
/**
* 网络环境
*/
public static network: string;
/**
* 接口请求类
*/
public static webapi: WebApi;
/**
* 发送错误
*/
public static send(data: ExceptionSendParams): void {
if (process.env.NODE_ENV !== 'production' || !Exception.productCode) {
if (Exception.productCode) {
console.log('异常上报的内容:');
console.log(data);
}
return;
}
const params: ExceptionData = {
col: data.col,
errorType: data.errorType || 1,
line: data.line,
content: data.content,
details: data.details,
productCode: data.productCode || Exception.productCode,
url: data.url,
userAgent,
lat: Exception.lat,
lng: Exception.lng,
account: Exception.account,
openId: Exception.openId,
version: Exception.version,
currentPage: getCurrentRoute(),
network: Exception.network
};
this.webapi.post({
api: Exception.apiname,
type: 'post',
contentType: 'application/json',
timeoutStr: 'none',
params,
success: () => null,
isCache: false
});
}
/**
* 解析catch的错误
*/
public static catchParse(e: Error): ExceptionData {
const details = e.stack.trim();
let startIndex = urlStartIndexForString(details);
let suffixIndex = details.indexOf('.js:') + 4;
let lineEndIndex = details.substr(suffixIndex).indexOf(':') + suffixIndex;
let endIndex = lineEndIndex + 6;
let path = details.substr(startIndex, endIndex - startIndex);
if (urlStartIndexForString(path, true) !== startIndex) {
startIndex = urlStartIndexForString(path, true);
path = path.substr(startIndex, endIndex - startIndex);
startIndex = 0;
suffixIndex = path.indexOf('.js:') + 4;
lineEndIndex = path.substr(suffixIndex).indexOf(':') + suffixIndex;
endIndex = lineEndIndex + 6;
}
const url = path.substr(startIndex, suffixIndex - startIndex - 1);
const line = path.substr(suffixIndex, lineEndIndex - suffixIndex);
const col = path.substr(lineEndIndex, endIndex - suffixIndex).replace(/[^0-9]/ig, '');
return {
col: parseInt(col),
line: parseInt(line),
url,
details: e.stack,
content: `name: ${e.name};
message: ${e.message};`,
errorType: 1,
userAgent,
lat: Exception.lat,
lng: Exception.lng,
account: Exception.account,
openId: Exception.openId,
version: Exception.version,
currentPage: getCurrentRoute(),
network: Exception.network
};
}
/**
* catch时发送错误
*/
public static catchSend(e: Error): void {
const data: ExceptionSendParams = Exception.catchParse(e);
if (process.env.NODE_ENV !== 'production') {
console.log('异常解析结果:');
console.log(data);
throw e;
} else {
Exception.send(data);
}
}
/**
* 监听异常
*/
public static listen(): void {
window.onerror = (msg: string, url: string, line: number, col: number, error: Error): boolean => {
//没有URL不上报!上报也不知道错误
if (msg !== 'Script error.' && !url) {
return true;
}
//采用异步的方式
//我遇到过在window.onunload进行ajax的堵塞上报
//由于客户端强制关闭webview导致这次堵塞上报有Network Error
//我猜测这里window.onerror的执行流在关闭前是必然执行的
//而离开文章之后的上报对于业务来说是可丢失的
//所以我把这里的执行流放到异步事件去执行
//脚本的异常数降低了10倍
setTimeout(function(): void {
const data: ExceptionData = {
productCode: Exception.productCode,
errorType: 1,
col: 0,
line: 0,
url: '',
content: '',
details: '',
userAgent,
lat: Exception.lat,
lng: Exception.lng,
account: Exception.account,
openId: Exception.openId,
version: Exception.version,
currentPage: getCurrentRoute(),
network: Exception.network
};
//不一定所有浏览器都支持col参数
col = col || (window.event && window.event['errorCharacter']) || 0;
data.url = url;
data.line = line;
data.col = col;
if (!!error && !!error.stack) {
//如果浏览器有堆栈信息
//直接使用
data.content = `name: ${error.name};
message: ${error.message};`;
data.details = error.stack;
} else if (!!arguments.callee) {
//尝试通过callee拿堆栈信息
let ext: any = [];
let f = arguments.callee.caller;
let c = 3;
//这里只拿三层堆栈信息
while (f && (--c > 0)) {
ext.push(f.toString());
if (f === f.caller) {
//如果有环
break;
}
f = f.caller;
}
ext = ext.join(',');
data.content = ext;
}
//把data上报到后台!
if (process.env.NODE_ENV !== 'production') {
console.log('onerror扑捉到的错误:');
console.log(data);
} else {
Exception.send(data);
}
}, 0);
if (process.env.NODE_ENV !== 'production') {
throw error;
} else {
return true;
}
};
}
}
export default Exception;