const USER_AGENT = 'shiroko-monitor/0.2 (lightweight uptime panel)'; export async function probeHttp(monitor) { const started = Date.now(); const timeoutMs = (monitor.timeout ?? 10) * 1000; try { // redirect: manual —— 保留 3xx 原始状态码交给 expectStatus 判定,避免跟随重定向掩盖异常 const res = await fetch(monitor.url, { method: monitor.method || 'GET', redirect: 'manual', signal: AbortSignal.timeout(timeoutMs), headers: { 'user-agent': USER_AGENT, accept: '*/*' }, }); const latency = Date.now() - started; const expect = monitor.expectStatus ?? [200]; const ok = expect.includes(res.status); return { status: ok ? 'up' : 'down', latency, code: res.status, detail: ok ? `HTTP ${res.status}` : `HTTP ${res.status}(期望 ${expect.join('/')})`, }; } catch (err) { const latency = Date.now() - started; let detail; if (err.name === 'TimeoutError') detail = `请求超时(>${timeoutMs / 1000}s)`; else if (err.cause?.code) detail = err.cause.code; else detail = err.message; return { status: 'down', latency, code: 0, detail }; } }