UNPKG

xys-monitor

Version:

A project named xys-monitor

120 lines (101 loc) 5.5 kB
import { hijack, getFullUrl, isCrossDomain, getCgidata } from './util' import { objectAssign } from './object' export default function (reportSys = {}) { reportSys = reportSys || {} let errTypeMap = reportSys.errTypeMap let _commonpostdata = { data: { } } hijack(XMLHttpRequest.prototype, 'open', function (...args) { //异常返回 实例对象中不一定有url 所以在open的时候 我们自己写上一个 this.openargs = args this._responseUrl = args[1] this._isCrossDomain = isCrossDomain(getFullUrl(args[1]), location.href) this._requestStartTime = (new Date()).getTime() }) hijack(XMLHttpRequest.prototype, 'send', function (...args) { //忽略自身上报cgii ajax请求报错 if (this._ignore) { return } let loadEvent = 'onreadystatechange' if (this.openargs.length > 0) { _commonpostdata.data.cgidata = getCgidata(this.openargs[0], this.openargs[1], ...args) } this._isSend = true // if (typeof window !== 'undefined' && window.XDomainRequest) { // loadEvent = 'onload'; // } //使用微任务劫持 为了兼容低版本jq /* eslint-disable-next-line no-new */ new Promise((resolve, reject) => { resolve() }).then(() => { //为了兼容3.x以上的jq if (this.onload) { loadEvent = 'onload' } hijack(this, loadEvent, function (...args) { //todo 判断超时、404等异常 let target = args[0].target || args[0].srcElement if (!target || target.readyState !== 4) { return } let wasteTime = (new Date()).getTime() - target._requestStartTime if (!('' + target.status).match(/^[1|2|3]/) && target.status !== 0) { reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: target._responseUrl + ' ' + target.statusText, errorType: errTypeMap['request_fail_error'] }), this) } else if (target.status === 0 && !(target.responseURL && target.responseURL.indexOf('file:') === 0)) { //该情况为跨域 // The request errored out and we didn't get a response, this will be // handled by onerror instead // With one exception: request that using file: protocol, most browsers // will return status as 0 even though it's a successful request if (this._isCrossDomain) { reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: 'Origin ' + target._responseUrl + ' is therefore not allowed access.', errorType: errTypeMap['cross_domain_error'] }), this) } } else if (reportSys.options.xhr && reportSys.options.xhr.slowtime && (wasteTime >= reportSys.options.xhr.slowtime)) { //慢速cgi上报 reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: target._responseUrl + ' is slow than ' + reportSys.options.xhr.slowtime + 'ms', errorType: errTypeMap['low_speed_error'] }), this) } else if (target.status === 200 && typeof target.response === 'string' && (target.response.indexOf('<title>错误</title>') !== -1 || (target.response.match(/^\{.*\}$/) && JSON.parse(target.response).info))) { //增加页面重定向 / 转发到error.html的错误监听 reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: target._responseUrl + ' is error', errorType: errTypeMap['request_fail_error'] }), this) } }) //jq自己利用settimeout实现了一个timeout abort机制 所以我们劫持xhr omtimeout是无效的 //目前已知的是jq不仅仅timeout的时候触发abort 如果检测到beforeSend返回的是false 也会abort //所以我们无法从xhr对象中获取是否有设置超时 hijack(this, 'abort', function (...args) { if (this._isSend) { //该情况为jq中的超时 reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: 'Origin ' + this._responseUrl + ' is abort.', errorType: errTypeMap['timeout_error'] }), this) } }) }).catch(err => { console.error('err', err) }) hijack(this, 'ontimeout', function (...args) { //获取_responseUrl并且上报 let target = args[0].target || args[0].srcElement reportSys.report.reportError(objectAssign(_commonpostdata, { errorMsg: target._responseUrl + ' is timeout ( responseTime > ' + target.timeout + 'ms )', errorType: errTypeMap['timeout_error'] }), this) }) }) }