weixin-devtools-mcp 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +101 -114
- package/build/MiniProgramContext.d.ts +307 -0
- package/build/MiniProgramContext.d.ts.map +1 -0
- package/build/MiniProgramContext.js +650 -0
- package/build/MiniProgramContext.js.map +1 -0
- package/build/collectors/Collector.d.ts +127 -0
- package/build/collectors/Collector.d.ts.map +1 -0
- package/build/collectors/Collector.js +252 -0
- package/build/collectors/Collector.js.map +1 -0
- package/build/collectors/ConsoleCollector.d.ts +104 -0
- package/build/collectors/ConsoleCollector.d.ts.map +1 -0
- package/build/collectors/ConsoleCollector.js +157 -0
- package/build/collectors/ConsoleCollector.js.map +1 -0
- package/build/collectors/NetworkCollector.d.ts +167 -0
- package/build/collectors/NetworkCollector.d.ts.map +1 -0
- package/build/collectors/NetworkCollector.js +265 -0
- package/build/collectors/NetworkCollector.js.map +1 -0
- package/build/collectors/index.d.ts +13 -0
- package/build/collectors/index.d.ts.map +1 -0
- package/build/collectors/index.js +17 -0
- package/build/collectors/index.js.map +1 -0
- package/build/config/tool-profile.d.ts +30 -0
- package/build/config/tool-profile.d.ts.map +1 -0
- package/build/config/tool-profile.js +138 -0
- package/build/config/tool-profile.js.map +1 -0
- package/build/connection/adapters.d.ts +3 -0
- package/build/connection/adapters.d.ts.map +1 -0
- package/build/connection/adapters.js +134 -0
- package/build/connection/adapters.js.map +1 -0
- package/build/connection/errors.d.ts +34 -0
- package/build/connection/errors.d.ts.map +1 -0
- package/build/connection/errors.js +101 -0
- package/build/connection/errors.js.map +1 -0
- package/build/connection/health-probe.d.ts +4 -0
- package/build/connection/health-probe.d.ts.map +1 -0
- package/build/connection/health-probe.js +60 -0
- package/build/connection/health-probe.js.map +1 -0
- package/build/connection/index.d.ts +6 -0
- package/build/connection/index.d.ts.map +1 -0
- package/build/connection/index.js +6 -0
- package/build/connection/index.js.map +1 -0
- package/build/connection/manager.d.ts +19 -0
- package/build/connection/manager.d.ts.map +1 -0
- package/build/connection/manager.js +198 -0
- package/build/connection/manager.js.map +1 -0
- package/build/connection/resolver.d.ts +3 -0
- package/build/connection/resolver.d.ts.map +1 -0
- package/build/connection/resolver.js +96 -0
- package/build/connection/resolver.js.map +1 -0
- package/build/connection/types.d.ts +95 -0
- package/build/connection/types.d.ts.map +1 -0
- package/build/connection/types.js +16 -0
- package/build/connection/types.js.map +1 -0
- package/build/formatters/consoleFormatter.d.ts +50 -0
- package/build/formatters/consoleFormatter.d.ts.map +1 -0
- package/build/formatters/consoleFormatter.js +116 -0
- package/build/formatters/consoleFormatter.js.map +1 -0
- package/build/formatters/snapshotFormatter.d.ts +41 -0
- package/build/formatters/snapshotFormatter.d.ts.map +1 -0
- package/build/formatters/snapshotFormatter.js +156 -0
- package/build/formatters/snapshotFormatter.js.map +1 -0
- package/build/index.d.ts +11 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +45 -9
- package/build/index.js.map +1 -0
- package/build/server.d.ts +7 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +70 -30
- package/build/server.js.map +1 -0
- package/build/tools/ToolDefinition.d.ts +215 -0
- package/build/tools/ToolDefinition.d.ts.map +1 -0
- package/build/tools/ToolDefinition.js +9 -7
- package/build/tools/ToolDefinition.js.map +1 -0
- package/build/tools/assert.d.ts +17 -0
- package/build/tools/assert.d.ts.map +1 -0
- package/build/tools/assert.js +8 -88
- package/build/tools/assert.js.map +1 -0
- package/build/tools/connection.d.ts +13 -0
- package/build/tools/connection.d.ts.map +1 -0
- package/build/tools/connection.js +332 -615
- package/build/tools/connection.js.map +1 -0
- package/build/tools/console.d.ts +20 -0
- package/build/tools/console.d.ts.map +1 -0
- package/build/tools/console.js +162 -152
- package/build/tools/console.js.map +1 -0
- package/build/tools/diagnose.d.ts +22 -0
- package/build/tools/diagnose.d.ts.map +1 -0
- package/build/tools/diagnose.js +400 -13
- package/build/tools/diagnose.js.map +1 -0
- package/build/tools/index.d.ts +6 -0
- package/build/tools/index.d.ts.map +1 -0
- package/build/tools/index.js +3 -77
- package/build/tools/index.js.map +1 -0
- package/build/tools/input.d.ts +21 -0
- package/build/tools/input.d.ts.map +1 -0
- package/build/tools/input.js +73 -139
- package/build/tools/input.js.map +1 -0
- package/build/tools/navigate.d.ts +21 -0
- package/build/tools/navigate.d.ts.map +1 -0
- package/build/tools/navigate.js +63 -126
- package/build/tools/navigate.js.map +1 -0
- package/build/tools/network.d.ts +17 -0
- package/build/tools/network.d.ts.map +1 -0
- package/build/tools/network.js +75 -887
- package/build/tools/network.js.map +1 -0
- package/build/tools/page.d.ts +13 -0
- package/build/tools/page.d.ts.map +1 -0
- package/build/tools/page.js +4 -1
- package/build/tools/page.js.map +1 -0
- package/build/tools/screenshot.d.ts +9 -0
- package/build/tools/screenshot.d.ts.map +1 -0
- package/build/tools/screenshot.js +3 -1
- package/build/tools/screenshot.js.map +1 -0
- package/build/tools/script.d.ts +6 -0
- package/build/tools/script.d.ts.map +1 -0
- package/build/tools/script.js +92 -0
- package/build/tools/script.js.map +1 -0
- package/build/tools/snapshot.d.ts +9 -0
- package/build/tools/snapshot.d.ts.map +1 -0
- package/build/tools/snapshot.js +78 -12
- package/build/tools/snapshot.js.map +1 -0
- package/build/tools/tools.d.ts +15 -0
- package/build/tools/tools.d.ts.map +1 -0
- package/build/tools/tools.js +62 -0
- package/build/tools/tools.js.map +1 -0
- package/build/tools.d.ts +431 -0
- package/build/tools.d.ts.map +1 -0
- package/build/tools.js +235 -117
- package/build/tools.js.map +1 -0
- package/build/types/errors.d.ts +189 -0
- package/build/types/errors.d.ts.map +1 -0
- package/build/types/errors.js +257 -0
- package/build/types/errors.js.map +1 -0
- package/build/utils/idGenerator.d.ts +21 -0
- package/build/utils/idGenerator.d.ts.map +1 -0
- package/build/utils/idGenerator.js +23 -0
- package/build/utils/idGenerator.js.map +1 -0
- package/package.json +34 -10
package/build/tools/network.js
CHANGED
|
@@ -2,811 +2,11 @@
|
|
|
2
2
|
* 网络请求监听工具
|
|
3
3
|
* 通过拦截 wx.request, wx.uploadFile, wx.downloadFile 实现网络监控
|
|
4
4
|
*/
|
|
5
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment -- wx 运行时对象在 evaluate 上下文中动态注入,需保持现有注释抑制。 */
|
|
5
6
|
import { z } from 'zod';
|
|
6
|
-
import { defineTool } from './ToolDefinition.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* 注意: 这个函数会被序列化后在小程序环境执行,不能使用闭包变量
|
|
10
|
-
* 保持函数简单,只记录信息然后调用原始方法
|
|
11
|
-
*/
|
|
12
|
-
function createRequestInterceptor() {
|
|
13
|
-
return function (options) {
|
|
14
|
-
// 初始化全局存储
|
|
15
|
-
// 关键修复: 在小程序环境中直接访问 wx 对象,不通过 globalThis
|
|
16
|
-
// wx 是小程序提供的全局对象,直接可用
|
|
17
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
18
|
-
const wxObj = (typeof wx !== 'undefined' ? wx : null);
|
|
19
|
-
if (!wxObj) {
|
|
20
|
-
// wx 对象不存在,无法记录,直接调用原始方法
|
|
21
|
-
return this.origin(options);
|
|
22
|
-
}
|
|
23
|
-
if (!wxObj.__networkLogs) {
|
|
24
|
-
wxObj.__networkLogs = [];
|
|
25
|
-
}
|
|
26
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
27
|
-
const startTime = Date.now();
|
|
28
|
-
// 包装 success 回调
|
|
29
|
-
const originalSuccess = options.success;
|
|
30
|
-
options.success = function (res) {
|
|
31
|
-
wxObj.__networkLogs.push({
|
|
32
|
-
id: requestId,
|
|
33
|
-
type: 'request',
|
|
34
|
-
url: options.url,
|
|
35
|
-
method: options.method || 'GET',
|
|
36
|
-
headers: options.header,
|
|
37
|
-
data: options.data,
|
|
38
|
-
statusCode: res.statusCode,
|
|
39
|
-
response: res.data,
|
|
40
|
-
duration: Date.now() - startTime,
|
|
41
|
-
timestamp: new Date().toISOString(),
|
|
42
|
-
success: true
|
|
43
|
-
});
|
|
44
|
-
if (originalSuccess)
|
|
45
|
-
originalSuccess(res);
|
|
46
|
-
};
|
|
47
|
-
// 包装 fail 回调
|
|
48
|
-
const originalFail = options.fail;
|
|
49
|
-
options.fail = function (err) {
|
|
50
|
-
wxObj.__networkLogs.push({
|
|
51
|
-
id: requestId,
|
|
52
|
-
type: 'request',
|
|
53
|
-
url: options.url,
|
|
54
|
-
method: options.method || 'GET',
|
|
55
|
-
headers: options.header,
|
|
56
|
-
data: options.data,
|
|
57
|
-
error: err.errMsg || String(err),
|
|
58
|
-
duration: Date.now() - startTime,
|
|
59
|
-
timestamp: new Date().toISOString(),
|
|
60
|
-
success: false
|
|
61
|
-
});
|
|
62
|
-
if (originalFail)
|
|
63
|
-
originalFail(err);
|
|
64
|
-
};
|
|
65
|
-
// 调用原始方法
|
|
66
|
-
return this.origin(options);
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* 创建 uploadFile 拦截器函数
|
|
71
|
-
*/
|
|
72
|
-
function createUploadFileInterceptor() {
|
|
73
|
-
return function (options) {
|
|
74
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
75
|
-
const wxObj = (typeof wx !== 'undefined' ? wx : null);
|
|
76
|
-
if (!wxObj) {
|
|
77
|
-
return this.origin(options);
|
|
78
|
-
}
|
|
79
|
-
if (!wxObj.__networkLogs) {
|
|
80
|
-
wxObj.__networkLogs = [];
|
|
81
|
-
}
|
|
82
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
83
|
-
const startTime = Date.now();
|
|
84
|
-
const originalSuccess = options.success;
|
|
85
|
-
options.success = function (res) {
|
|
86
|
-
wxObj.__networkLogs.push({
|
|
87
|
-
id: requestId,
|
|
88
|
-
type: 'uploadFile',
|
|
89
|
-
url: options.url,
|
|
90
|
-
headers: options.header,
|
|
91
|
-
data: {
|
|
92
|
-
filePath: options.filePath,
|
|
93
|
-
name: options.name,
|
|
94
|
-
formData: options.formData
|
|
95
|
-
},
|
|
96
|
-
statusCode: res.statusCode,
|
|
97
|
-
response: res.data,
|
|
98
|
-
duration: Date.now() - startTime,
|
|
99
|
-
timestamp: new Date().toISOString(),
|
|
100
|
-
success: true
|
|
101
|
-
});
|
|
102
|
-
if (originalSuccess)
|
|
103
|
-
originalSuccess(res);
|
|
104
|
-
};
|
|
105
|
-
const originalFail = options.fail;
|
|
106
|
-
options.fail = function (err) {
|
|
107
|
-
wxObj.__networkLogs.push({
|
|
108
|
-
id: requestId,
|
|
109
|
-
type: 'uploadFile',
|
|
110
|
-
url: options.url,
|
|
111
|
-
headers: options.header,
|
|
112
|
-
data: {
|
|
113
|
-
filePath: options.filePath,
|
|
114
|
-
name: options.name,
|
|
115
|
-
formData: options.formData
|
|
116
|
-
},
|
|
117
|
-
error: err.errMsg || String(err),
|
|
118
|
-
duration: Date.now() - startTime,
|
|
119
|
-
timestamp: new Date().toISOString(),
|
|
120
|
-
success: false
|
|
121
|
-
});
|
|
122
|
-
if (originalFail)
|
|
123
|
-
originalFail(err);
|
|
124
|
-
};
|
|
125
|
-
return this.origin(options);
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* 创建 downloadFile 拦截器函数
|
|
130
|
-
*/
|
|
131
|
-
function createDownloadFileInterceptor() {
|
|
132
|
-
return function (options) {
|
|
133
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
134
|
-
const wxObj = (typeof wx !== 'undefined' ? wx : null);
|
|
135
|
-
if (!wxObj) {
|
|
136
|
-
return this.origin(options);
|
|
137
|
-
}
|
|
138
|
-
if (!wxObj.__networkLogs) {
|
|
139
|
-
wxObj.__networkLogs = [];
|
|
140
|
-
}
|
|
141
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
142
|
-
const startTime = Date.now();
|
|
143
|
-
const originalSuccess = options.success;
|
|
144
|
-
options.success = function (res) {
|
|
145
|
-
wxObj.__networkLogs.push({
|
|
146
|
-
id: requestId,
|
|
147
|
-
type: 'downloadFile',
|
|
148
|
-
url: options.url,
|
|
149
|
-
headers: options.header,
|
|
150
|
-
statusCode: res.statusCode,
|
|
151
|
-
response: {
|
|
152
|
-
tempFilePath: res.tempFilePath,
|
|
153
|
-
filePath: res.filePath
|
|
154
|
-
},
|
|
155
|
-
duration: Date.now() - startTime,
|
|
156
|
-
timestamp: new Date().toISOString(),
|
|
157
|
-
success: true
|
|
158
|
-
});
|
|
159
|
-
if (originalSuccess)
|
|
160
|
-
originalSuccess(res);
|
|
161
|
-
};
|
|
162
|
-
const originalFail = options.fail;
|
|
163
|
-
options.fail = function (err) {
|
|
164
|
-
wxObj.__networkLogs.push({
|
|
165
|
-
id: requestId,
|
|
166
|
-
type: 'downloadFile',
|
|
167
|
-
url: options.url,
|
|
168
|
-
headers: options.header,
|
|
169
|
-
error: err.errMsg || String(err),
|
|
170
|
-
duration: Date.now() - startTime,
|
|
171
|
-
timestamp: new Date().toISOString(),
|
|
172
|
-
success: false
|
|
173
|
-
});
|
|
174
|
-
if (originalFail)
|
|
175
|
-
originalFail(err);
|
|
176
|
-
};
|
|
177
|
-
return this.origin(options);
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* 启动网络监听工具
|
|
182
|
-
*
|
|
183
|
-
* 使用evaluate()直接在小程序环境注入拦截代码
|
|
184
|
-
* 这种方式可以绕过Mpx等框架的API缓存问题
|
|
185
|
-
*/
|
|
186
|
-
export const startNetworkMonitoringTool = defineTool({
|
|
187
|
-
name: 'start_network_monitoring',
|
|
188
|
-
description: '启动对微信小程序网络请求的监听,拦截 wx.request、wx.uploadFile、wx.downloadFile',
|
|
189
|
-
schema: z.object({
|
|
190
|
-
clearExisting: z.boolean().optional().default(false).describe('是否清除已有的网络请求记录'),
|
|
191
|
-
}),
|
|
192
|
-
annotations: {
|
|
193
|
-
audience: ['developers'],
|
|
194
|
-
},
|
|
195
|
-
handler: async (request, response, context) => {
|
|
196
|
-
const { clearExisting } = request.params;
|
|
197
|
-
if (!context.miniProgram) {
|
|
198
|
-
throw new Error('请先连接到微信开发者工具');
|
|
199
|
-
}
|
|
200
|
-
if (context.networkStorage.isMonitoring) {
|
|
201
|
-
response.appendResponseLine('网络监听已在运行中');
|
|
202
|
-
response.appendResponseLine(`当前已记录 ${context.networkStorage.requests.length} 个网络请求`);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
// 清除现有记录
|
|
206
|
-
if (clearExisting) {
|
|
207
|
-
context.networkStorage.requests = [];
|
|
208
|
-
}
|
|
209
|
-
try {
|
|
210
|
-
// 使用evaluate()方式在小程序环境中直接注入拦截代码
|
|
211
|
-
// 支持双模式:Mpx框架拦截器 + wx.request回退方案
|
|
212
|
-
await context.miniProgram.evaluate(function (shouldClear) {
|
|
213
|
-
// @ts-ignore - wx在小程序环境中可用
|
|
214
|
-
if (typeof wx === 'undefined') {
|
|
215
|
-
throw new Error('wx对象不可用');
|
|
216
|
-
}
|
|
217
|
-
// 初始化或清除存储
|
|
218
|
-
// @ts-ignore
|
|
219
|
-
if (!wx.__networkLogs || shouldClear) {
|
|
220
|
-
// @ts-ignore
|
|
221
|
-
wx.__networkLogs = [];
|
|
222
|
-
}
|
|
223
|
-
// 检查是否已经注入过拦截器
|
|
224
|
-
// @ts-ignore
|
|
225
|
-
if (wx.__networkInterceptorsInstalled && !shouldClear) {
|
|
226
|
-
console.log('[MCP-DEBUG] 拦截器已安装,跳过重复安装');
|
|
227
|
-
return; // 已安装,跳过
|
|
228
|
-
}
|
|
229
|
-
// 如果需要清除,先删除旧的标记
|
|
230
|
-
if (shouldClear) {
|
|
231
|
-
console.log('[MCP-DEBUG] 强制重装:清除旧的安装标记');
|
|
232
|
-
// @ts-ignore
|
|
233
|
-
delete wx.__networkInterceptorsInstalled;
|
|
234
|
-
// 同时清空pending队列和config缓存
|
|
235
|
-
// @ts-ignore
|
|
236
|
-
wx.__pendingQueue = [];
|
|
237
|
-
// @ts-ignore
|
|
238
|
-
wx.__requestConfigMap = {};
|
|
239
|
-
}
|
|
240
|
-
// ===== 模式1:检测并使用Mpx框架拦截器 =====
|
|
241
|
-
console.log('[MCP-DEBUG] 开始检测Mpx框架...');
|
|
242
|
-
// @ts-ignore - getApp is available in WeChat miniprogram environment
|
|
243
|
-
const app = getApp();
|
|
244
|
-
console.log('[MCP-DEBUG] getApp() 结果:', {
|
|
245
|
-
hasApp: !!app,
|
|
246
|
-
appType: typeof app,
|
|
247
|
-
hasXfetch: !!(app && app.$xfetch),
|
|
248
|
-
xfetchType: app && app.$xfetch ? typeof app.$xfetch : 'undefined'
|
|
249
|
-
});
|
|
250
|
-
const hasMpxFetch = app &&
|
|
251
|
-
app.$xfetch &&
|
|
252
|
-
app.$xfetch.interceptors &&
|
|
253
|
-
typeof app.$xfetch.interceptors.request.use === 'function';
|
|
254
|
-
console.log('[MCP-DEBUG] Mpx检测结果:', {
|
|
255
|
-
hasMpxFetch: hasMpxFetch,
|
|
256
|
-
hasInterceptors: !!(app && app.$xfetch && app.$xfetch.interceptors),
|
|
257
|
-
hasRequestUse: !!(app && app.$xfetch && app.$xfetch.interceptors && app.$xfetch.interceptors.request),
|
|
258
|
-
hasResponseUse: !!(app && app.$xfetch && app.$xfetch.interceptors && app.$xfetch.interceptors.response)
|
|
259
|
-
});
|
|
260
|
-
if (hasMpxFetch) {
|
|
261
|
-
console.log('[MCP] ✅ 检测到Mpx框架,使用getApp().$xfetch拦截器模式');
|
|
262
|
-
console.log('[MCP] 📝 使用Pending队列方案解决业务拦截器改变响应结构的问题');
|
|
263
|
-
// 初始化pending队列和config缓存
|
|
264
|
-
// @ts-ignore
|
|
265
|
-
if (!wx.__pendingQueue) {
|
|
266
|
-
// @ts-ignore
|
|
267
|
-
wx.__pendingQueue = [];
|
|
268
|
-
}
|
|
269
|
-
// @ts-ignore
|
|
270
|
-
if (!wx.__requestConfigMap) {
|
|
271
|
-
// @ts-ignore
|
|
272
|
-
wx.__requestConfigMap = {};
|
|
273
|
-
}
|
|
274
|
-
// 如果需要重装,清空旧的Mpx拦截器handlers(防止累加)
|
|
275
|
-
if (shouldClear) {
|
|
276
|
-
console.log('[MCP-DEBUG] 准备清空handlers, shouldClear=', shouldClear);
|
|
277
|
-
console.log('[MCP-DEBUG] request拦截器结构:', {
|
|
278
|
-
hasInterceptors: !!app.$xfetch.interceptors.request,
|
|
279
|
-
hasHandlers: !!app.$xfetch.interceptors.request.handlers,
|
|
280
|
-
handlersType: typeof app.$xfetch.interceptors.request.handlers,
|
|
281
|
-
handlersIsArray: Array.isArray(app.$xfetch.interceptors.request.handlers)
|
|
282
|
-
});
|
|
283
|
-
// @ts-ignore
|
|
284
|
-
if (app.$xfetch.interceptors.request && app.$xfetch.interceptors.request.handlers) {
|
|
285
|
-
// @ts-ignore
|
|
286
|
-
app.$xfetch.interceptors.request.handlers = [];
|
|
287
|
-
console.log('[MCP-DEBUG] ✅ 已清空旧的request拦截器handlers');
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
console.log('[MCP-DEBUG] ⚠️ request.handlers不存在或不是数组');
|
|
291
|
-
}
|
|
292
|
-
// @ts-ignore
|
|
293
|
-
if (app.$xfetch.interceptors.response && app.$xfetch.interceptors.response.handlers) {
|
|
294
|
-
// @ts-ignore
|
|
295
|
-
app.$xfetch.interceptors.response.handlers = [];
|
|
296
|
-
console.log('[MCP-DEBUG] ✅ 已清空旧的response拦截器handlers');
|
|
297
|
-
}
|
|
298
|
-
else {
|
|
299
|
-
console.log('[MCP-DEBUG] ⚠️ response.handlers不存在或不是数组');
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
// 请求拦截器 - 记录请求开始并缓存config
|
|
303
|
-
// @ts-ignore
|
|
304
|
-
getApp().$xfetch.interceptors.request.use(function (config) {
|
|
305
|
-
const requestId = 'mpx_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
306
|
-
const startTime = Date.now();
|
|
307
|
-
console.log('[MCP-DEBUG] 🔵 请求拦截器被触发:', {
|
|
308
|
-
requestId: requestId,
|
|
309
|
-
method: config.method,
|
|
310
|
-
url: config.url,
|
|
311
|
-
hasData: !!config.data,
|
|
312
|
-
hasParams: !!config.params,
|
|
313
|
-
timestamp: new Date().toISOString()
|
|
314
|
-
});
|
|
315
|
-
// 保存完整的config到缓存(因为响应拦截器可能拿不到requestConfig)
|
|
316
|
-
// @ts-ignore
|
|
317
|
-
wx.__requestConfigMap[requestId] = {
|
|
318
|
-
url: config.url,
|
|
319
|
-
method: config.method || 'GET',
|
|
320
|
-
header: config.header || config.headers,
|
|
321
|
-
data: config.data,
|
|
322
|
-
params: config.params,
|
|
323
|
-
timeout: config.timeout || 30000
|
|
324
|
-
};
|
|
325
|
-
// 添加到pending队列(FIFO)
|
|
326
|
-
// @ts-ignore
|
|
327
|
-
wx.__pendingQueue.push({
|
|
328
|
-
id: requestId,
|
|
329
|
-
url: config.url,
|
|
330
|
-
method: config.method || 'GET',
|
|
331
|
-
startTime: startTime
|
|
332
|
-
});
|
|
333
|
-
// 清理超时的pending请求(避免队列堆积)
|
|
334
|
-
const timeout = config.timeout || 30000;
|
|
335
|
-
// @ts-ignore
|
|
336
|
-
wx.__pendingQueue = wx.__pendingQueue.filter((item) => Date.now() - item.startTime < timeout + 5000 // 额外5秒容错
|
|
337
|
-
);
|
|
338
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
339
|
-
wx.__networkLogs.push({
|
|
340
|
-
id: requestId,
|
|
341
|
-
type: 'request',
|
|
342
|
-
method: config.method || 'GET',
|
|
343
|
-
url: config.url,
|
|
344
|
-
headers: config.header || config.headers,
|
|
345
|
-
data: config.data,
|
|
346
|
-
params: config.params,
|
|
347
|
-
timestamp: new Date(startTime).toISOString(),
|
|
348
|
-
source: 'getApp().$xfetch',
|
|
349
|
-
pending: true, // 标记为待完成状态
|
|
350
|
-
success: undefined // 初始化success字段,避免状态判断问题
|
|
351
|
-
});
|
|
352
|
-
// @ts-ignore - wx在小程序环境可用
|
|
353
|
-
console.log('[MCP-DEBUG] ✅ 请求已记录, pending队列:', wx.__pendingQueue.length, ', 日志数:', wx.__networkLogs.length);
|
|
354
|
-
return config; // 必须返回config继续请求链
|
|
355
|
-
});
|
|
356
|
-
// 响应拦截器 - 使用Pending队列匹配请求/响应
|
|
357
|
-
// @ts-ignore
|
|
358
|
-
getApp().$xfetch.interceptors.response.use(function onSuccess(data) {
|
|
359
|
-
try {
|
|
360
|
-
// 注意: data可能只是业务数据(如{goodsList, tripId}),而不是完整的response对象
|
|
361
|
-
// 因为业务拦截器(commonResInterceptor)改变了响应结构
|
|
362
|
-
console.log('[MCP-DEBUG] 🟢 响应拦截器被触发(成功)');
|
|
363
|
-
console.log('[MCP-DEBUG] 🔍 响应数据类型:', typeof data, ', 键:', Object.keys(data || {}));
|
|
364
|
-
// 从Pending队列获取最早的请求(FIFO匹配)
|
|
365
|
-
// @ts-ignore
|
|
366
|
-
const requestInfo = wx.__pendingQueue.shift();
|
|
367
|
-
if (!requestInfo) {
|
|
368
|
-
console.log('[MCP-DEBUG] ⚠️ Pending队列为空,无法匹配请求');
|
|
369
|
-
return data;
|
|
370
|
-
}
|
|
371
|
-
const duration = Date.now() - requestInfo.startTime;
|
|
372
|
-
console.log('[MCP-DEBUG] 📦 从队列取出请求:', {
|
|
373
|
-
requestId: requestInfo.id,
|
|
374
|
-
url: requestInfo.url,
|
|
375
|
-
method: requestInfo.method,
|
|
376
|
-
duration: duration + 'ms'
|
|
377
|
-
});
|
|
378
|
-
// 从缓存获取完整的请求配置
|
|
379
|
-
// @ts-ignore
|
|
380
|
-
const savedConfig = wx.__requestConfigMap[requestInfo.id];
|
|
381
|
-
if (!savedConfig) {
|
|
382
|
-
console.log('[MCP-DEBUG] ⚠️ 未找到缓存的config');
|
|
383
|
-
}
|
|
384
|
-
// @ts-ignore
|
|
385
|
-
// 找到对应的日志记录并更新
|
|
386
|
-
let logIndex = wx.__networkLogs.findIndex((log) => log.id === requestInfo.id);
|
|
387
|
-
// 增强:如果按ID找不到,尝试按URL和时间窗口匹配(fallback策略)
|
|
388
|
-
if (logIndex === -1) {
|
|
389
|
-
console.log('[MCP-DEBUG] ⚠️ 按ID未找到日志,尝试URL匹配...');
|
|
390
|
-
// @ts-ignore
|
|
391
|
-
logIndex = wx.__networkLogs.findIndex((log) => log.url === requestInfo.url &&
|
|
392
|
-
log.pending === true &&
|
|
393
|
-
Math.abs(new Date(log.timestamp).getTime() - requestInfo.startTime) < 10000 // 10秒窗口
|
|
394
|
-
);
|
|
395
|
-
if (logIndex !== -1) {
|
|
396
|
-
console.log('[MCP-DEBUG] ✅ 通过URL匹配找到日志, 索引:', logIndex);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
if (logIndex !== -1) {
|
|
400
|
-
// @ts-ignore
|
|
401
|
-
const existingLog = wx.__networkLogs[logIndex];
|
|
402
|
-
// @ts-ignore
|
|
403
|
-
wx.__networkLogs[logIndex] = {
|
|
404
|
-
...existingLog,
|
|
405
|
-
statusCode: 200, // 能到这里说明成功
|
|
406
|
-
response: data, // 只能拿到业务数据
|
|
407
|
-
duration: duration,
|
|
408
|
-
completedAt: new Date().toISOString(),
|
|
409
|
-
pending: false,
|
|
410
|
-
success: true
|
|
411
|
-
};
|
|
412
|
-
console.log('[MCP-DEBUG] ✅ 请求记录已更新 (合并响应), 索引:', logIndex);
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
console.log('[MCP-DEBUG] ❌ 完全未找到匹配的日志记录, requestId:', requestInfo.id, ', url:', requestInfo.url);
|
|
416
|
-
}
|
|
417
|
-
// 清理config缓存
|
|
418
|
-
// @ts-ignore
|
|
419
|
-
if (savedConfig) {
|
|
420
|
-
// @ts-ignore
|
|
421
|
-
delete wx.__requestConfigMap[requestInfo.id];
|
|
422
|
-
}
|
|
423
|
-
// @ts-ignore - wx在小程序环境可用
|
|
424
|
-
console.log('[MCP-DEBUG] 📊 状态 - 日志:', wx.__networkLogs.length, ', pending:', wx.__pendingQueue.length, ', config缓存:', Object.keys(wx.__requestConfigMap || {}).length);
|
|
425
|
-
return data; // 必须返回data继续拦截器链
|
|
426
|
-
}
|
|
427
|
-
catch (error) {
|
|
428
|
-
console.log('[MCP-DEBUG] ❌ 响应拦截器异常:', error);
|
|
429
|
-
return data; // 即使出错也要返回data,不能中断业务逻辑
|
|
430
|
-
}
|
|
431
|
-
}, function onError(error) {
|
|
432
|
-
try {
|
|
433
|
-
console.log('[MCP-DEBUG] 🔴 响应拦截器被触发(错误)');
|
|
434
|
-
console.log('[MCP-DEBUG] 🔍 错误对象:', error);
|
|
435
|
-
// 从Pending队列获取最早的请求(FIFO匹配)
|
|
436
|
-
// @ts-ignore
|
|
437
|
-
const requestInfo = wx.__pendingQueue.shift();
|
|
438
|
-
if (!requestInfo) {
|
|
439
|
-
console.log('[MCP-DEBUG] ⚠️ Pending队列为空,无法匹配错误请求');
|
|
440
|
-
return Promise.reject(error);
|
|
441
|
-
}
|
|
442
|
-
const duration = Date.now() - requestInfo.startTime;
|
|
443
|
-
console.log('[MCP-DEBUG] 📦 从队列取出请求(错误):', {
|
|
444
|
-
requestId: requestInfo.id,
|
|
445
|
-
url: requestInfo.url,
|
|
446
|
-
error: error.errMsg || error.msg || error.message || String(error),
|
|
447
|
-
duration: duration + 'ms'
|
|
448
|
-
});
|
|
449
|
-
// @ts-ignore
|
|
450
|
-
// 找到对应的日志记录并更新
|
|
451
|
-
let logIndex = wx.__networkLogs.findIndex((log) => log.id === requestInfo.id);
|
|
452
|
-
// 增强:如果按ID找不到,尝试按URL和时间窗口匹配(fallback策略)
|
|
453
|
-
if (logIndex === -1) {
|
|
454
|
-
console.log('[MCP-DEBUG] ⚠️ 按ID未找到日志(错误场景),尝试URL匹配...');
|
|
455
|
-
// @ts-ignore
|
|
456
|
-
logIndex = wx.__networkLogs.findIndex((log) => log.url === requestInfo.url &&
|
|
457
|
-
log.pending === true &&
|
|
458
|
-
Math.abs(new Date(log.timestamp).getTime() - requestInfo.startTime) < 10000 // 10秒窗口
|
|
459
|
-
);
|
|
460
|
-
if (logIndex !== -1) {
|
|
461
|
-
console.log('[MCP-DEBUG] ✅ 通过URL匹配找到日志(错误场景), 索引:', logIndex);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
if (logIndex !== -1) {
|
|
465
|
-
// @ts-ignore
|
|
466
|
-
const existingLog = wx.__networkLogs[logIndex];
|
|
467
|
-
// @ts-ignore
|
|
468
|
-
wx.__networkLogs[logIndex] = {
|
|
469
|
-
...existingLog,
|
|
470
|
-
error: error.errMsg || error.msg || error.message || String(error),
|
|
471
|
-
statusCode: error.status || error.statusCode,
|
|
472
|
-
duration: duration,
|
|
473
|
-
completedAt: new Date().toISOString(),
|
|
474
|
-
pending: false,
|
|
475
|
-
success: false
|
|
476
|
-
};
|
|
477
|
-
console.log('[MCP-DEBUG] ✅ 请求记录已更新 (合并错误), 索引:', logIndex);
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
console.log('[MCP-DEBUG] ❌ 完全未找到匹配的日志记录(错误场景), requestId:', requestInfo.id, ', url:', requestInfo.url);
|
|
481
|
-
}
|
|
482
|
-
// 清理config缓存
|
|
483
|
-
// @ts-ignore
|
|
484
|
-
if (wx.__requestConfigMap && wx.__requestConfigMap[requestInfo.id]) {
|
|
485
|
-
// @ts-ignore
|
|
486
|
-
delete wx.__requestConfigMap[requestInfo.id];
|
|
487
|
-
}
|
|
488
|
-
// @ts-ignore - wx在小程序环境可用
|
|
489
|
-
console.log('[MCP-DEBUG] 📊 状态 - 日志:', wx.__networkLogs.length, ', pending:', wx.__pendingQueue.length);
|
|
490
|
-
return Promise.reject(error); // 保持错误传播
|
|
491
|
-
}
|
|
492
|
-
catch (innerError) {
|
|
493
|
-
console.log('[MCP-DEBUG] ❌ 错误拦截器异常:', innerError);
|
|
494
|
-
return Promise.reject(error); // 即使出错也要传播原始错误,不能中断业务逻辑
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
498
|
-
wx.__networkInterceptorsInstalled = 'mpx';
|
|
499
|
-
console.log('[MCP] ✅ Mpx拦截器安装完成');
|
|
500
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
501
|
-
console.log('[MCP-DEBUG] 拦截器已标记为已安装: wx.__networkInterceptorsInstalled =', wx.__networkInterceptorsInstalled);
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
console.log('[MCP] ⚠️ 未检测到Mpx框架或$xfetch不可用');
|
|
505
|
-
}
|
|
506
|
-
// ===== 模式2:wx.request回退方案(用于非Mpx框架或直接调用wx API的场景) =====
|
|
507
|
-
if (!hasMpxFetch) {
|
|
508
|
-
console.log('[MCP] ⚠️ 未检测到Mpx框架,使用wx.request拦截模式');
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
console.log('[MCP-DEBUG] Mpx模式下,同时安装wx.request回退拦截器(双保险)');
|
|
512
|
-
}
|
|
513
|
-
// 保存原始方法引用(通过getter获取)
|
|
514
|
-
// @ts-ignore
|
|
515
|
-
const _originalRequest = wx.request;
|
|
516
|
-
// @ts-ignore
|
|
517
|
-
const _originalUploadFile = wx.uploadFile;
|
|
518
|
-
// @ts-ignore
|
|
519
|
-
const _originalDownloadFile = wx.downloadFile;
|
|
520
|
-
console.log('[MCP-DEBUG] 原始方法类型:', {
|
|
521
|
-
requestType: typeof _originalRequest,
|
|
522
|
-
uploadFileType: typeof _originalUploadFile,
|
|
523
|
-
downloadFileType: typeof _originalDownloadFile
|
|
524
|
-
});
|
|
525
|
-
// 拦截 wx.request
|
|
526
|
-
// 关键:先删除getter属性,然后重新定义为普通属性
|
|
527
|
-
// @ts-ignore
|
|
528
|
-
delete wx.request;
|
|
529
|
-
// @ts-ignore
|
|
530
|
-
Object.defineProperty(wx, 'request', {
|
|
531
|
-
configurable: true,
|
|
532
|
-
enumerable: true,
|
|
533
|
-
writable: true,
|
|
534
|
-
value: function (options) {
|
|
535
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
536
|
-
const startTime = Date.now();
|
|
537
|
-
console.log('[MCP-DEBUG] 🔵 wx.request 被调用:', {
|
|
538
|
-
requestId: requestId,
|
|
539
|
-
method: options.method || 'GET',
|
|
540
|
-
url: options.url,
|
|
541
|
-
hasData: !!options.data,
|
|
542
|
-
timestamp: new Date().toISOString()
|
|
543
|
-
});
|
|
544
|
-
// 包装success回调
|
|
545
|
-
const originalSuccess = options.success;
|
|
546
|
-
options.success = function (res) {
|
|
547
|
-
console.log('[MCP-DEBUG] 🟢 wx.request 成功回调:', {
|
|
548
|
-
requestId: requestId,
|
|
549
|
-
statusCode: res.statusCode,
|
|
550
|
-
duration: Date.now() - startTime
|
|
551
|
-
});
|
|
552
|
-
// @ts-ignore
|
|
553
|
-
wx.__networkLogs.push({
|
|
554
|
-
id: requestId,
|
|
555
|
-
type: 'request',
|
|
556
|
-
url: options.url,
|
|
557
|
-
method: options.method || 'GET',
|
|
558
|
-
headers: options.header,
|
|
559
|
-
data: options.data,
|
|
560
|
-
statusCode: res.statusCode,
|
|
561
|
-
response: res.data,
|
|
562
|
-
duration: Date.now() - startTime,
|
|
563
|
-
timestamp: new Date().toISOString(),
|
|
564
|
-
source: 'wx.request',
|
|
565
|
-
success: true
|
|
566
|
-
});
|
|
567
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
568
|
-
console.log('[MCP-DEBUG] ✅ wx.request 已记录, 当前总数:', wx.__networkLogs.length);
|
|
569
|
-
if (originalSuccess)
|
|
570
|
-
originalSuccess.call(this, res);
|
|
571
|
-
};
|
|
572
|
-
// 包装fail回调
|
|
573
|
-
const originalFail = options.fail;
|
|
574
|
-
options.fail = function (err) {
|
|
575
|
-
console.log('[MCP-DEBUG] 🔴 wx.request 失败回调:', {
|
|
576
|
-
requestId: requestId,
|
|
577
|
-
error: err.errMsg,
|
|
578
|
-
duration: Date.now() - startTime
|
|
579
|
-
});
|
|
580
|
-
// @ts-ignore
|
|
581
|
-
wx.__networkLogs.push({
|
|
582
|
-
id: requestId,
|
|
583
|
-
type: 'request',
|
|
584
|
-
url: options.url,
|
|
585
|
-
method: options.method || 'GET',
|
|
586
|
-
headers: options.header,
|
|
587
|
-
data: options.data,
|
|
588
|
-
error: err.errMsg || String(err),
|
|
589
|
-
duration: Date.now() - startTime,
|
|
590
|
-
timestamp: new Date().toISOString(),
|
|
591
|
-
source: 'wx.request',
|
|
592
|
-
success: false
|
|
593
|
-
});
|
|
594
|
-
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
595
|
-
console.log('[MCP-DEBUG] ✅ wx.request 错误已记录, 当前总数:', wx.__networkLogs.length);
|
|
596
|
-
if (originalFail)
|
|
597
|
-
originalFail.call(this, err);
|
|
598
|
-
};
|
|
599
|
-
// 调用原始方法
|
|
600
|
-
return _originalRequest.call(this, options);
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
console.log('[MCP-DEBUG] ✅ wx.request 拦截器已安装');
|
|
604
|
-
// 拦截 wx.uploadFile
|
|
605
|
-
// 关键:先删除getter属性
|
|
606
|
-
// @ts-ignore
|
|
607
|
-
delete wx.uploadFile;
|
|
608
|
-
// @ts-ignore
|
|
609
|
-
Object.defineProperty(wx, 'uploadFile', {
|
|
610
|
-
configurable: true,
|
|
611
|
-
enumerable: true,
|
|
612
|
-
writable: true,
|
|
613
|
-
value: function (options) {
|
|
614
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
615
|
-
const startTime = Date.now();
|
|
616
|
-
const originalSuccess = options.success;
|
|
617
|
-
options.success = function (res) {
|
|
618
|
-
// @ts-ignore
|
|
619
|
-
wx.__networkLogs.push({
|
|
620
|
-
id: requestId,
|
|
621
|
-
type: 'uploadFile',
|
|
622
|
-
url: options.url,
|
|
623
|
-
headers: options.header,
|
|
624
|
-
data: {
|
|
625
|
-
filePath: options.filePath,
|
|
626
|
-
name: options.name,
|
|
627
|
-
formData: options.formData
|
|
628
|
-
},
|
|
629
|
-
statusCode: res.statusCode,
|
|
630
|
-
response: res.data,
|
|
631
|
-
duration: Date.now() - startTime,
|
|
632
|
-
timestamp: new Date().toISOString(),
|
|
633
|
-
source: 'wx.uploadFile',
|
|
634
|
-
success: true
|
|
635
|
-
});
|
|
636
|
-
if (originalSuccess)
|
|
637
|
-
originalSuccess.call(this, res);
|
|
638
|
-
};
|
|
639
|
-
const originalFail = options.fail;
|
|
640
|
-
options.fail = function (err) {
|
|
641
|
-
// @ts-ignore
|
|
642
|
-
wx.__networkLogs.push({
|
|
643
|
-
id: requestId,
|
|
644
|
-
type: 'uploadFile',
|
|
645
|
-
url: options.url,
|
|
646
|
-
headers: options.header,
|
|
647
|
-
data: {
|
|
648
|
-
filePath: options.filePath,
|
|
649
|
-
name: options.name,
|
|
650
|
-
formData: options.formData
|
|
651
|
-
},
|
|
652
|
-
error: err.errMsg || String(err),
|
|
653
|
-
duration: Date.now() - startTime,
|
|
654
|
-
timestamp: new Date().toISOString(),
|
|
655
|
-
source: 'wx.uploadFile',
|
|
656
|
-
success: false
|
|
657
|
-
});
|
|
658
|
-
if (originalFail)
|
|
659
|
-
originalFail.call(this, err);
|
|
660
|
-
};
|
|
661
|
-
return _originalUploadFile.call(this, options);
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
// 拦截 wx.downloadFile
|
|
665
|
-
// 关键:先删除getter属性
|
|
666
|
-
// @ts-ignore
|
|
667
|
-
delete wx.downloadFile;
|
|
668
|
-
// @ts-ignore
|
|
669
|
-
Object.defineProperty(wx, 'downloadFile', {
|
|
670
|
-
configurable: true,
|
|
671
|
-
enumerable: true,
|
|
672
|
-
writable: true,
|
|
673
|
-
value: function (options) {
|
|
674
|
-
const requestId = 'req_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
|
|
675
|
-
const startTime = Date.now();
|
|
676
|
-
const originalSuccess = options.success;
|
|
677
|
-
options.success = function (res) {
|
|
678
|
-
// @ts-ignore
|
|
679
|
-
wx.__networkLogs.push({
|
|
680
|
-
id: requestId,
|
|
681
|
-
type: 'downloadFile',
|
|
682
|
-
url: options.url,
|
|
683
|
-
headers: options.header,
|
|
684
|
-
statusCode: res.statusCode,
|
|
685
|
-
response: {
|
|
686
|
-
tempFilePath: res.tempFilePath,
|
|
687
|
-
filePath: res.filePath
|
|
688
|
-
},
|
|
689
|
-
duration: Date.now() - startTime,
|
|
690
|
-
timestamp: new Date().toISOString(),
|
|
691
|
-
source: 'wx.downloadFile',
|
|
692
|
-
success: true
|
|
693
|
-
});
|
|
694
|
-
if (originalSuccess)
|
|
695
|
-
originalSuccess.call(this, res);
|
|
696
|
-
};
|
|
697
|
-
const originalFail = options.fail;
|
|
698
|
-
options.fail = function (err) {
|
|
699
|
-
// @ts-ignore
|
|
700
|
-
wx.__networkLogs.push({
|
|
701
|
-
id: requestId,
|
|
702
|
-
type: 'downloadFile',
|
|
703
|
-
url: options.url,
|
|
704
|
-
headers: options.header,
|
|
705
|
-
error: err.errMsg || String(err),
|
|
706
|
-
duration: Date.now() - startTime,
|
|
707
|
-
timestamp: new Date().toISOString(),
|
|
708
|
-
source: 'wx.downloadFile',
|
|
709
|
-
success: false
|
|
710
|
-
});
|
|
711
|
-
if (originalFail)
|
|
712
|
-
originalFail.call(this, err);
|
|
713
|
-
};
|
|
714
|
-
return _originalDownloadFile.call(this, options);
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
// 标记拦截器已安装
|
|
718
|
-
// @ts-ignore
|
|
719
|
-
wx.__networkInterceptorsInstalled = true;
|
|
720
|
-
}, clearExisting);
|
|
721
|
-
// 设置监听状态
|
|
722
|
-
context.networkStorage.isMonitoring = true;
|
|
723
|
-
context.networkStorage.startTime = new Date().toISOString();
|
|
724
|
-
response.appendResponseLine('✅ 网络监听已启动(使用增强型拦截)');
|
|
725
|
-
response.appendResponseLine(`监听开始时间: ${context.networkStorage.startTime}`);
|
|
726
|
-
response.appendResponseLine(`清除历史记录: ${clearExisting ? '是' : '否'}`);
|
|
727
|
-
response.appendResponseLine('');
|
|
728
|
-
response.appendResponseLine('已拦截以下方法:');
|
|
729
|
-
response.appendResponseLine(' - wx.request');
|
|
730
|
-
response.appendResponseLine(' - wx.uploadFile');
|
|
731
|
-
response.appendResponseLine(' - wx.downloadFile');
|
|
732
|
-
response.appendResponseLine('');
|
|
733
|
-
response.appendResponseLine('💡 使用 evaluate() 方式注入,可绕过 Mpx 等框架限制');
|
|
734
|
-
response.appendResponseLine(' 所有网络请求都将被捕获,使用 get_network_requests 查看');
|
|
735
|
-
}
|
|
736
|
-
catch (error) {
|
|
737
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
738
|
-
throw new Error(`启动网络监听失败: ${errorMessage}`);
|
|
739
|
-
}
|
|
740
|
-
},
|
|
741
|
-
});
|
|
742
|
-
/**
|
|
743
|
-
* 停止网络监听工具
|
|
744
|
-
*
|
|
745
|
-
* 注意:使用evaluate()注入的拦截器无法完全恢复
|
|
746
|
-
* 只能清除标记,实际拦截器会继续工作
|
|
747
|
-
*/
|
|
748
|
-
export const stopNetworkMonitoringTool = defineTool({
|
|
749
|
-
name: 'stop_network_monitoring',
|
|
750
|
-
description: '停止对微信小程序网络请求的监听,恢复原始的网络方法',
|
|
751
|
-
schema: z.object({}),
|
|
752
|
-
annotations: {
|
|
753
|
-
audience: ['developers'],
|
|
754
|
-
},
|
|
755
|
-
handler: async (request, response, context) => {
|
|
756
|
-
if (!context.miniProgram) {
|
|
757
|
-
throw new Error('请先连接到微信开发者工具');
|
|
758
|
-
}
|
|
759
|
-
if (!context.networkStorage.isMonitoring) {
|
|
760
|
-
response.appendResponseLine('网络监听未在运行');
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
try {
|
|
764
|
-
// 从小程序环境读取最终的请求数据并清除标记
|
|
765
|
-
const result = await context.miniProgram.evaluate(function () {
|
|
766
|
-
// @ts-ignore
|
|
767
|
-
const wxObj = typeof wx !== 'undefined' ? wx : null;
|
|
768
|
-
if (!wxObj) {
|
|
769
|
-
return { logs: [], success: false };
|
|
770
|
-
}
|
|
771
|
-
const logs = wxObj.__networkLogs || [];
|
|
772
|
-
// 清除安装标记(允许重新安装)
|
|
773
|
-
// 注意:实际的拦截器无法恢复,因为我们使用了Object.defineProperty
|
|
774
|
-
// 这是evaluate()方式的一个限制,但好处是可以绕过框架缓存
|
|
775
|
-
wxObj.__networkInterceptorsInstalled = false;
|
|
776
|
-
return { logs, success: true };
|
|
777
|
-
});
|
|
778
|
-
if (!result.success) {
|
|
779
|
-
throw new Error('无法访问wx对象');
|
|
780
|
-
}
|
|
781
|
-
const logs = result.logs;
|
|
782
|
-
// 更新监听状态
|
|
783
|
-
context.networkStorage.isMonitoring = false;
|
|
784
|
-
response.appendResponseLine('✅ 网络监听已停止');
|
|
785
|
-
response.appendResponseLine(`监听期间收集到 ${logs.length} 个网络请求`);
|
|
786
|
-
// 统计各类型请求数量
|
|
787
|
-
const stats = logs.reduce((acc, req) => {
|
|
788
|
-
acc[req.type] = (acc[req.type] || 0) + 1;
|
|
789
|
-
return acc;
|
|
790
|
-
}, {});
|
|
791
|
-
response.appendResponseLine('');
|
|
792
|
-
response.appendResponseLine('请求类型统计:');
|
|
793
|
-
if (stats.request)
|
|
794
|
-
response.appendResponseLine(` - request: ${stats.request}`);
|
|
795
|
-
if (stats.uploadFile)
|
|
796
|
-
response.appendResponseLine(` - uploadFile: ${stats.uploadFile}`);
|
|
797
|
-
if (stats.downloadFile)
|
|
798
|
-
response.appendResponseLine(` - downloadFile: ${stats.downloadFile}`);
|
|
799
|
-
response.appendResponseLine('');
|
|
800
|
-
response.appendResponseLine('⚠️ 注意: 拦截器将继续工作(evaluate方式的特性)');
|
|
801
|
-
response.appendResponseLine(' 使用 clear_network_requests 清除数据');
|
|
802
|
-
response.appendResponseLine(' 使用 start_network_monitoring 重新开始记录');
|
|
803
|
-
}
|
|
804
|
-
catch (error) {
|
|
805
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
806
|
-
throw new Error(`停止网络监听失败: ${errorMessage}`);
|
|
807
|
-
}
|
|
808
|
-
},
|
|
809
|
-
});
|
|
7
|
+
import { defineTool, ToolCategory } from './ToolDefinition.js';
|
|
8
|
+
// 注意: start_network_monitoring 和 stop_network_monitoring 已移除
|
|
9
|
+
// 网络监听在连接时自动启动,无需手动管理
|
|
810
10
|
/**
|
|
811
11
|
* 获取网络请求工具
|
|
812
12
|
*/
|
|
@@ -821,6 +21,7 @@ export const getNetworkRequestsTool = defineTool({
|
|
|
821
21
|
since: z.string().optional().describe('获取指定时间之后的记录,格式:ISO 8601'),
|
|
822
22
|
}),
|
|
823
23
|
annotations: {
|
|
24
|
+
category: ToolCategory.NETWORK,
|
|
824
25
|
audience: ['developers'],
|
|
825
26
|
},
|
|
826
27
|
handler: async (request, response, context) => {
|
|
@@ -982,93 +183,80 @@ export const getNetworkRequestsTool = defineTool({
|
|
|
982
183
|
},
|
|
983
184
|
});
|
|
984
185
|
/**
|
|
985
|
-
*
|
|
186
|
+
* 停止网络监听工具
|
|
986
187
|
*/
|
|
987
|
-
export const
|
|
988
|
-
name: '
|
|
989
|
-
description: '
|
|
990
|
-
schema: z.object({
|
|
188
|
+
export const stopNetworkMonitoringTool = defineTool({
|
|
189
|
+
name: 'stop_network_monitoring',
|
|
190
|
+
description: '停止网络请求监听,禁用拦截器',
|
|
191
|
+
schema: z.object({
|
|
192
|
+
clearLogs: z.boolean().optional().default(false).describe('是否同时清空已收集的日志'),
|
|
193
|
+
}),
|
|
991
194
|
annotations: {
|
|
195
|
+
category: ToolCategory.NETWORK,
|
|
992
196
|
audience: ['developers'],
|
|
993
197
|
},
|
|
994
198
|
handler: async (request, response, context) => {
|
|
199
|
+
const { clearLogs } = request.params;
|
|
995
200
|
if (!context.miniProgram) {
|
|
996
201
|
throw new Error('请先连接到微信开发者工具');
|
|
997
202
|
}
|
|
203
|
+
if (!context.networkStorage) {
|
|
204
|
+
throw new Error('网络存储未初始化');
|
|
205
|
+
}
|
|
998
206
|
try {
|
|
999
|
-
|
|
207
|
+
// 设置禁用标志
|
|
208
|
+
await context.miniProgram.evaluate(function () {
|
|
1000
209
|
// @ts-ignore - wx is available in WeChat miniprogram environment
|
|
1001
210
|
const wxObj = typeof wx !== 'undefined' ? wx : null;
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
// @ts-ignore - getApp is available in WeChat miniprogram environment
|
|
1006
|
-
const hasGetApp = typeof getApp !== 'undefined';
|
|
1007
|
-
// @ts-ignore - getApp is available in WeChat miniprogram environment
|
|
1008
|
-
const app = hasGetApp ? getApp() : null;
|
|
1009
|
-
const diagnosticInfo = {
|
|
1010
|
-
environment: {
|
|
1011
|
-
hasWx: !!wxObj,
|
|
1012
|
-
hasGetApp: hasGetApp,
|
|
1013
|
-
},
|
|
1014
|
-
interceptor: {
|
|
1015
|
-
installed: !!(wxObj && wxObj.__networkInterceptorsInstalled),
|
|
1016
|
-
hasNetworkLogs: !!(wxObj && wxObj.__networkLogs),
|
|
1017
|
-
networkLogsLength: wxObj && wxObj.__networkLogs ? wxObj.__networkLogs.length : 0,
|
|
1018
|
-
},
|
|
1019
|
-
mpx: {
|
|
1020
|
-
hasGetApp: hasGetApp,
|
|
1021
|
-
hasApp: !!app,
|
|
1022
|
-
has$xfetch: !!(app && app.$xfetch),
|
|
1023
|
-
},
|
|
1024
|
-
networkLogs: wxObj && wxObj.__networkLogs ? wxObj.__networkLogs.slice(-5) : [],
|
|
1025
|
-
};
|
|
1026
|
-
console.log('[INTERCEPTOR-DIAGNOSE] 诊断信息:', JSON.stringify(diagnosticInfo, null, 2));
|
|
1027
|
-
console.log('[INTERCEPTOR-DIAGNOSE] === 诊断完成 ===');
|
|
1028
|
-
return diagnosticInfo;
|
|
211
|
+
if (wxObj) {
|
|
212
|
+
wxObj.__networkInterceptorsDisabled = true;
|
|
213
|
+
}
|
|
1029
214
|
});
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
response.appendResponseLine('');
|
|
1045
|
-
if (result.networkLogs && result.networkLogs.length > 0) {
|
|
1046
|
-
response.appendResponseLine(`最近${result.networkLogs.length}条网络日志:`);
|
|
1047
|
-
result.networkLogs.forEach((log, index) => {
|
|
1048
|
-
response.appendResponseLine(` ${index + 1}. [${log.type}] ${log.url || log.method}`);
|
|
215
|
+
// 更新本地状态
|
|
216
|
+
context.networkStorage.isMonitoring = false;
|
|
217
|
+
let clearedCount = 0;
|
|
218
|
+
if (clearLogs) {
|
|
219
|
+
// 清空远程日志
|
|
220
|
+
clearedCount = await context.miniProgram.evaluate(function () {
|
|
221
|
+
// @ts-ignore
|
|
222
|
+
const wxObj = typeof wx !== 'undefined' ? wx : null;
|
|
223
|
+
if (wxObj && wxObj.__networkLogs) {
|
|
224
|
+
const count = wxObj.__networkLogs.length;
|
|
225
|
+
wxObj.__networkLogs = [];
|
|
226
|
+
return count;
|
|
227
|
+
}
|
|
228
|
+
return 0;
|
|
1049
229
|
});
|
|
1050
230
|
}
|
|
231
|
+
response.appendResponseLine('=== 网络监听已停止 ===');
|
|
232
|
+
response.appendResponseLine(`监听状态: 已停止`);
|
|
233
|
+
if (clearLogs) {
|
|
234
|
+
response.appendResponseLine(`已清空日志: ${clearedCount} 条`);
|
|
235
|
+
}
|
|
236
|
+
response.appendResponseLine('');
|
|
237
|
+
response.appendResponseLine('💡 提示: 使用 reconnect_devtools 重新连接可恢复监听');
|
|
1051
238
|
}
|
|
1052
239
|
catch (error) {
|
|
1053
240
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1054
|
-
throw new Error(
|
|
241
|
+
throw new Error(`停止网络监听失败: ${errorMessage}`);
|
|
1055
242
|
}
|
|
1056
243
|
},
|
|
1057
244
|
});
|
|
1058
245
|
/**
|
|
1059
|
-
*
|
|
246
|
+
* 清空网络请求记录工具
|
|
1060
247
|
*/
|
|
1061
248
|
export const clearNetworkRequestsTool = defineTool({
|
|
1062
249
|
name: 'clear_network_requests',
|
|
1063
|
-
description: '
|
|
250
|
+
description: '清空已收集的网络请求记录',
|
|
1064
251
|
schema: z.object({
|
|
1065
|
-
|
|
252
|
+
clearRemote: z.boolean().optional().default(true).describe('是否同时清空小程序端的日志'),
|
|
1066
253
|
}),
|
|
1067
254
|
annotations: {
|
|
255
|
+
category: ToolCategory.NETWORK,
|
|
1068
256
|
audience: ['developers'],
|
|
1069
257
|
},
|
|
1070
258
|
handler: async (request, response, context) => {
|
|
1071
|
-
const {
|
|
259
|
+
const { clearRemote } = request.params;
|
|
1072
260
|
if (!context.miniProgram) {
|
|
1073
261
|
throw new Error('请先连接到微信开发者工具');
|
|
1074
262
|
}
|
|
@@ -1076,36 +264,36 @@ export const clearNetworkRequestsTool = defineTool({
|
|
|
1076
264
|
throw new Error('网络存储未初始化');
|
|
1077
265
|
}
|
|
1078
266
|
try {
|
|
1079
|
-
//
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
267
|
+
// 记录当前数量
|
|
268
|
+
const localCountBefore = context.networkStorage.requests?.length || 0;
|
|
269
|
+
// 清空本地存储
|
|
270
|
+
context.networkStorage.requests = [];
|
|
271
|
+
// 清空远程日志
|
|
272
|
+
let remoteCount = 0;
|
|
273
|
+
if (clearRemote) {
|
|
274
|
+
remoteCount = await context.miniProgram.evaluate(function () {
|
|
275
|
+
// @ts-ignore
|
|
276
|
+
const wxObj = typeof wx !== 'undefined' ? wx : null;
|
|
277
|
+
if (wxObj && wxObj.__networkLogs) {
|
|
278
|
+
const count = wxObj.__networkLogs.length;
|
|
279
|
+
wxObj.__networkLogs = [];
|
|
280
|
+
return count;
|
|
281
|
+
}
|
|
1090
282
|
return 0;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
const clearedCount = beforeCount - afterCount;
|
|
1101
|
-
response.appendResponseLine('✅ 网络请求记录清除完成');
|
|
1102
|
-
response.appendResponseLine(`清除类型: ${type}`);
|
|
1103
|
-
response.appendResponseLine(`清除数量: ${clearedCount} 条`);
|
|
1104
|
-
response.appendResponseLine(`剩余数量: ${afterCount} 条`);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
response.appendResponseLine('=== 网络请求记录已清空 ===');
|
|
286
|
+
response.appendResponseLine(`本地清空: ${localCountBefore} 条`);
|
|
287
|
+
if (clearRemote) {
|
|
288
|
+
response.appendResponseLine(`远程清空: ${remoteCount} 条`);
|
|
289
|
+
}
|
|
290
|
+
response.appendResponseLine('');
|
|
291
|
+
response.appendResponseLine('💡 提示: 网络监听仍在运行,新的请求会继续被收集');
|
|
1105
292
|
}
|
|
1106
293
|
catch (error) {
|
|
1107
294
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1108
|
-
throw new Error(
|
|
295
|
+
throw new Error(`清空网络请求失败: ${errorMessage}`);
|
|
1109
296
|
}
|
|
1110
297
|
},
|
|
1111
298
|
});
|
|
299
|
+
//# sourceMappingURL=network.js.map
|