feat(panel web): 调试日志——api() 每请求计时/失败详录(NOT_JSON 附原始内容头 300B)+route 切换日志,控制台过滤 [mp]
This commit is contained in:
1 parent
908fc53805
commit
7a405866af
1 file changed
+21
-1
@@ -136,6 +136,16 @@
|
|||||||
$('#offline-banner').hidden = !!ok;
|
$('#offline-banner').hidden = !!ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------- 调试日志(浏览器控制台可见,过滤 [mp]) ---------------- */
|
||||||
|
function dbg() {
|
||||||
|
const a = Array.from(arguments);
|
||||||
|
console.log.apply(console, ['[mp]'].concat(a));
|
||||||
|
}
|
||||||
|
function dbgErr() {
|
||||||
|
const a = Array.from(arguments);
|
||||||
|
console.warn.apply(console, ['[mp][ERR]'].concat(a));
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------- API 客户端 ---------------- */
|
/* ---------------- API 客户端 ---------------- */
|
||||||
// 返回 {code,message,status} 形异常;网络/非 JSON → 视为断连
|
// 返回 {code,message,status} 形异常;网络/非 JSON → 视为断连
|
||||||
async function api(method, path, body) {
|
async function api(method, path, body) {
|
||||||
@@ -151,25 +161,34 @@
|
|||||||
init.body = JSON.stringify(body);
|
init.body = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
if (Object.keys(headers).length) init.headers = headers;
|
if (Object.keys(headers).length) init.headers = headers;
|
||||||
|
const t0 = performance.now();
|
||||||
try {
|
try {
|
||||||
res = await fetch(path, init);
|
res = await fetch(path, init);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
dbgErr(method || 'GET', path, '网络层失败:', e && e.message);
|
||||||
setConn(false);
|
setConn(false);
|
||||||
throw { code: 'NETWORK', message: '后端未连接', status: 0 };
|
throw { code: 'NETWORK', message: '后端未连接', status: 0 };
|
||||||
}
|
}
|
||||||
|
const ms = Math.round(performance.now() - t0);
|
||||||
|
/* 先读原文再解析:非 JSON 时能拿到原始内容前 300 字节进控制台 */
|
||||||
|
let text = '';
|
||||||
|
try { text = await res.text(); } catch (e) { /* 读体失败走 NOT_JSON */ }
|
||||||
let json = null;
|
let json = null;
|
||||||
try { json = await res.json(); } catch (e) { json = null; }
|
try { json = text ? JSON.parse(text) : null; } catch (e) { json = null; }
|
||||||
if (!json || typeof json.ok !== 'boolean') {
|
if (!json || typeof json.ok !== 'boolean') {
|
||||||
// 静态服务器返回 HTML / 404 等
|
// 静态服务器返回 HTML / 404 等
|
||||||
|
dbgErr(method || 'GET', path, 'HTTP', res.status, ms + 'ms', '非 JSON 响应, 原始内容头:', text.slice(0, 300));
|
||||||
setConn(res.ok ? true : false);
|
setConn(res.ok ? true : false);
|
||||||
throw { code: 'NOT_JSON', message: '后端返回了非 JSON 响应(HTTP ' + res.status + ')', status: res.status };
|
throw { code: 'NOT_JSON', message: '后端返回了非 JSON 响应(HTTP ' + res.status + ')', status: res.status };
|
||||||
}
|
}
|
||||||
if (!json.ok) {
|
if (!json.ok) {
|
||||||
setConn(true);
|
setConn(true);
|
||||||
const code = (json.error && json.error.code) || 'ERROR';
|
const code = (json.error && json.error.code) || 'ERROR';
|
||||||
|
dbgErr(method || 'GET', path, 'HTTP', res.status, ms + 'ms', '后端错误:', code, (json.error && json.error.message) || '');
|
||||||
if (code === 'UNAUTHORIZED') authRequired(); // 会话失效/未认证 → 弹登录页
|
if (code === 'UNAUTHORIZED') authRequired(); // 会话失效/未认证 → 弹登录页
|
||||||
throw { code: code, message: (json.error && json.error.message) || ('后端错误 ' + code), status: res.status };
|
throw { code: code, message: (json.error && json.error.message) || ('后端错误 ' + code), status: res.status };
|
||||||
}
|
}
|
||||||
|
if (ms > 800) dbg(method || 'GET', path, '慢响应', ms + 'ms');
|
||||||
setConn(true);
|
setConn(true);
|
||||||
return json.data;
|
return json.data;
|
||||||
}
|
}
|
||||||
@@ -2321,6 +2340,7 @@
|
|||||||
const id = (location.hash || '#/home').replace('#/', '').split('?')[0] || 'home';
|
const id = (location.hash || '#/home').replace('#/', '').split('?')[0] || 'home';
|
||||||
const r = ROUTES[id] || ROUTES.home;
|
const r = ROUTES[id] || ROUTES.home;
|
||||||
state.route = id;
|
state.route = id;
|
||||||
|
dbg('route →', id);
|
||||||
stopPerf();
|
stopPerf();
|
||||||
stopAudio();
|
stopAudio();
|
||||||
stopNet();
|
stopNet();
|
||||||
|
|||||||
Reference in new issue
Block a user