javascript
复制代码
// ==UserScript==
// @name 接口修改脚本
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 通用接口拦截和响应修改脚本,支持自定义配置
// @author You
// @match *://*/*
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// 测试环境账号与生产环境标识(业务场景,你可以自定义)
const currentAccount = "acc1";
const accountConf = {
"acc1": {
"总人数": 400,
"deptMemberCount": {
"部门1": 150,
"部门2": 80,
},
},
"acc2": {
"总人数": 3574,
"deptMemberCount": {
"部门1": 3380,
"部门2": 1256,
},
}
}
const config = accountConf[currentAccount] || accountConf["acc1"];
// 用于存储请求信息的Map
const requestMap = new Map();
// 接口地址与修改回调函数的映射
// 接口地址使用的是 url.includes 方式匹配,可根据需要修改
// 回调函数接收两个参数:response(响应数据对象),requestInfo(请求信息对象)
const API_CONFIG = {
'get_sub_depts_page': function (response, requestInfo) {
if (!response.result) return response;
const list = response.result.list;
for (let i = 0; i < list.length; i++) {
if (list[i]['name'] in config['deptMemberCount']) {
list[i].memberCount = config['deptMemberCount'][list[i]['name']];
continue;
}
}
return response;
},
'statistic_realtime': function (response, requestInfo) {
if (!response.result) return response;
response.result.activeCount = config['总人数'] - 1;
response.result.memCount = config['总人数'];
return response;
},
// ...
};
// XHR 拦截
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
// 存储请求信息
requestMap.set(this, {
method: method,
url: url,
body: null // XHR的body会在send时设置
});
// 查找匹配的接口配置
let matchedCallback = null;
for (const [path, callback] of Object.entries(API_CONFIG)) {
if (url.includes(path)) {
console.log(`拦截到接口: ${url}`);
matchedCallback = callback;
break;
}
}
if (matchedCallback) {
const originalOnReadyStateChange = this.onreadystatechange;
const xhr = this;
this.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
const requestInfo = requestMap.get(xhr) || {};
const modifiedResponse = matchedCallback(response, requestInfo);
Object.defineProperty(xhr, 'responseText', {
writable: true,
value: JSON.stringify(modifiedResponse)
});
Object.defineProperty(xhr, 'response', {
writable: true,
value: modifiedResponse
});
console.log(`xhr - ${url} - 已修改`);
} catch (e) {
console.error('修改响应失败:', e);
}
}
if (originalOnReadyStateChange) {
originalOnReadyStateChange.apply(this, arguments);
}
};
}
originalOpen.apply(this, arguments);
};
// XHR send 拦截,用于获取请求体
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (body) {
// 更新请求信息中的body
const requestInfo = requestMap.get(this);
if (requestInfo) {
requestInfo.body = body;
}
return originalSend.apply(this, arguments);
};
// Fetch 拦截
const originalFetch = window.fetch;
window.unsafeWindow.fetch = function (input, init) {
const url = typeof input === 'string' ? input : input.url;
const method = (init && init.method) || 'GET';
const body = (init && init.body) || null;
// 查找匹配的接口配置
let matchedCallback = null;
for (const [path, callback] of Object.entries(API_CONFIG)) {
if (url.includes(path)) {
console.log(`拦截到fetch请求: ${url}`);
matchedCallback = callback;
break;
}
}
if (!matchedCallback) {
return originalFetch(input, init);
}
// 创建请求信息对象
const requestInfo = {
method: method,
url: url,
body: body
};
return originalFetch(input, init).then(response => {
return response.text().then(text => {
try {
const data = JSON.parse(text);
const modifiedData = matchedCallback(data, requestInfo);
const modifiedText = JSON.stringify(modifiedData);
console.log(`fetch - ${url} - 已修改`);
return new Response(modifiedText, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
} catch (e) {
console.error('修改fetch响应失败:', e);
return new Response(text, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
});
});
};
console.log('接口修改脚本已加载,当前配置的接口数量:', Object.keys(API_CONFIG).length);
})();