From 0b9902b495d6a8f01da1817f2f79bdcd30eeae9a Mon Sep 17 00:00:00 2001 From: posimai Date: Tue, 31 Mar 2026 10:07:41 +0900 Subject: [PATCH] fix(atlas): skip http:// health checks from https context (mixed content warning) Vercel-hosted Atlas (HTTPS) was attempting HEAD requests to http:// internal endpoints (Gitea, Syncthing), causing browsers to show insecure connection warning. Now skips those requests silently; status stays at last known value. Co-Authored-By: Claude Sonnet 4.6 --- index.html | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index 5e02dfa..5b9fe5a 100644 --- a/index.html +++ b/index.html @@ -2009,7 +2009,10 @@ async function runHealthCheckAll() { } } else { const result = await checkUrlHealth(node.url); - next = result === 'offline' ? 'inactive' : 'active'; + // 'skipped' = HTTP endpoint from HTTPS context — leave status unchanged + if (result !== 'skipped') { + next = result === 'offline' ? 'inactive' : 'active'; + } nodeHealthCache.delete(node.id); } @@ -2036,6 +2039,9 @@ async function runHealthCheckAll() { } async function checkUrlHealth(url) { + // HTTPS ページから HTTP エンドポイントへのリクエストは混合コンテンツとしてブロックされる + // → ブラウザが「保護されていない通信」警告を出すため、スキップして 'skipped' を返す + if (location.protocol === 'https:' && url.startsWith('http:')) return 'skipped'; try { const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), 7000); @@ -2518,14 +2524,19 @@ async function checkNodeHealth(nodeId, url) { } } else { // /api/health なし → 従来の HEAD リクエスト - try { - const ctrl = new AbortController(); - const timer = setTimeout(() => ctrl.abort(), 6000); - const res = await fetch(url, { method: 'HEAD', mode: 'no-cors', signal: ctrl.signal }); - clearTimeout(timer); - result = res.type === 'opaque' ? 'limited' : (res.ok ? 'online' : 'offline'); - } catch (e) { - result = 'offline'; + // HTTP endpoint from HTTPS context はブロックされるのでスキップ + if (location.protocol === 'https:' && url && url.startsWith('http:')) { + result = 'limited'; + } else { + try { + const ctrl = new AbortController(); + const timer = setTimeout(() => ctrl.abort(), 6000); + const res = await fetch(url, { method: 'HEAD', mode: 'no-cors', signal: ctrl.signal }); + clearTimeout(timer); + result = res.type === 'opaque' ? 'limited' : (res.ok ? 'online' : 'offline'); + } catch (e) { + result = 'offline'; + } } }