闽公网安备 35020302035485号
fetch 可以与 AbortController 搭配使用来取消请求。
(function() {
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
this._url = url; // 保存请求的URL
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
this.addEventListener('load', function() {
if (this.status >= 200 && this.status < 300) {
// 请求成功,上报成功信息
reportRequest('success', this._url, this.status, this.responseText);
} else {
// 请求失败,上报失败信息
reportRequest('failure', this._url, this.status, this.responseText);
}
});
this.addEventListener('error', function() {
// 请求错误,上报错误信息
reportRequest('error', this._url, this.status, this.statusText);
});
return originalSend.apply(this, arguments);
};
function reportRequest(type, url, status, response) {
// 这里进行上报,可以通过fetch或其他方式发送上报请求
console.log(`Request ${type}: ${url}, Status: ${status}, Response: ${response}`);
// 例子:fetch('/report', { method: 'POST', body: JSON.stringify({ type, url, status, response }) })
}
})();
那fetch如何实现监听呢?同样也是重写。(function() {
const originalFetch = window.fetch;
window.fetch = function() {
const args = arguments;
const url = args[0];
// 堆代码 duidaima.com
return originalFetch.apply(this, arguments)
.then(response => {
if (response.ok) {
// 请求成功,上报成功信息
response.clone().text().then(responseText => {
reportRequest('success', url, response.status, responseText);
});
} else {
// 请求失败,上报失败信息
response.clone().text().then(responseText => {
reportRequest('failure', url, response.status, responseText);
});
}
return response;
})
.catch(error => {
// 请求错误,上报错误信息
reportRequest('error', url, 0, error.message);
throw error;
});
};
function reportRequest(type, url, status, response) {
// 这里进行上报,可以通过fetch或其他方式发送上报请求
console.log(`Request ${type}: ${url}, Status: ${status}, Response: ${response}`);
// 例子:fetch('/report', { method: 'POST', body: JSON.stringify({ type, url, status, response }) })
}
})();
看到这里,其实实现类似ARMS这样的API请求,很简单,ARMS底层一定也是依赖类似这样的代码块来实现原子能力,在此基础上,设计了一套可插拔、模块化的系统监控架构,来进行系统全方位的监听。import TraceApiPlugin from '@ali/trace-plugin-api';
import TracePerfPlugin from '@ali/trace-plugin-perf';
import TracePvPlugin from '@ali/trace-plugin-pv';
import TraceResourceErrorPlugin from '@ali/trace-plugin-resource-error';
import TraceSdk from '@ali/trace-sdk';
import { isProd } from './constants';
const traceEnv = isProd ? 'prod' : 'test';
const trace = TraceSdk({
pid: 'relax-drink', // 必填 请在https://arms.alibaba-inc.com/arms/project/create 申请项目ID
errorEnable: true, // 非必填 默认已经开启了js报错,若关闭则设置errorEnable:false
env: traceEnv, // 可选 prod | pre | daily | string
ignoreErrors: [/^Script error\.?$/], // 可选,用法参考"初始化配置说明"
aplusUrl: 's-gm.mmstat.com', // 可选 默认s-gm.mmstat.com, 海外(新加坡)埋点配置 sg.mmstat.com
plugins: [
// 使用插件
[TracePvPlugin, { autoPV: false }],
[TraceApiPlugin, { sampling: 0.1 }], // 接口监控插件
[TracePerfPlugin, { enableLCP: true }],
[TraceResourceErrorPlugin], // 前端资源异常监控插件
],
useSendBeacon: false,
});
// 执行
trace.install();
代码块中包含了ARMS的其他能力,包括js error、性能、资源的监控,我们本节只基于接口请求做示例。function TraceSdk(config) {
// 默认配置
const defaultConfig = {
errorEnable: true,
env: 'prod',
aplusUrl: 's-gm.mmstat.com',
useSendBeacon: false,
ignoreErrors: [],
plugins: [],
};
// 合并用户提供的配置和默认配置
const finalConfig = { ...defaultConfig, ...config };
// 初始化插件
function initializePlugins(plugins) {
plugins.forEach(([PluginConstructor, options]) => {
const plugin = new PluginConstructor(options);
plugin.initialize();
});
}
// 安装SDK
function install() {
console.log('Trace SDK 安装中...');
setupErrorHandling();
initializePlugins(finalConfig.plugins);
}
// 设置错误处理(简单实现)
function setupErrorHandling() {
if (finalConfig.errorEnable) {
window.addEventListener('error', (event) => {
const errorMessage = event.message;
if (
!finalConfig.ignoreErrors.some((regex) => regex.test(errorMessage))
) {
console.error('捕获到错误:', errorMessage);
// 可在此执行错误报告逻辑
}
});
}
}
// 公开的API
return {
install,
};
}
// 示例插件构造函数(模拟)
function TraceApiPlugin(options) {
this.options = options || {};
this.initialize = function () {
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
this._url = url; // 保存请求的URL
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function (body) {
this.addEventListener('load', function () {
if (this.status >= 200 && this.status < 300) {
// 请求成功,上报成功信息
reportRequest('success', this._url, this.status, this.responseText);
} else {
// 请求失败,上报失败信息
reportRequest('failure', this._url, this.status, this.responseText);
}
});
this.addEventListener('error', function () {
// 请求错误,上报错误信息
reportRequest('error', this._url, this.status, this.statusText);
});
return originalSend.apply(this, arguments);
};
function reportRequest(type, url, status, response) {
// 这里进行上报,可以通过fetch或其他方式发送上报请求
console.log(
`Request ${type}: ${url}, Status: ${status}, Response: ${response}`,
);
// 例子:fetch('/report', { method: 'POST', body: JSON.stringify({ type, url, status, response }) })
}
};
}
如果想启用更多的能力,则ARMS内部肯定会有类似TraceJsErrorPlugin、TracePerfPlugin等,直接在初始化阶段注入到TraceSDK实例初始化即可。