콘솔 에러/경고
증상: 브라우저 콘솔에 빨간 에러, 노란 경고가 반복적으로 출력됩니다.
진단: 에러 메시지와 스택트레이스를 기록하고, 가장 위의 원인부터 추적하세요.
중요: 사용자 인터랙션 차단 가능
본 문서는 W3C 표준과 웹 접근성 지침(WCAG), 모던 브라우저 호환성을 고려하여 웹사이트 오류를 진단하고 해결하는 실무형 가이드입니다. 개발, QA, 운영팀이 함께 사용할 수 있도록 체크리스트와 예시 코드를 포함합니다.
핵심: 오류 해결은 재현 → 관측 → 원인 분리 → 수정 → 검증 → 회귀 테스트의 순환입니다. 표준 준수와 접근성은 문제 예방의 가장 강력한 기본기입니다.
증상: 브라우저 콘솔에 빨간 에러, 노란 경고가 반복적으로 출력됩니다.
진단: 에러 메시지와 스택트레이스를 기록하고, 가장 위의 원인부터 추적하세요.
중요: 사용자 인터랙션 차단 가능
증상: 요청이 4xx/5xx 또는 CORS 차단으로 실패합니다.
진단: 상태코드, 응답 헤더, 프리플라이트(OPTIONS) 확인.
경고: 데이터 불일치 발생 가능
증상: 특정 해상도/브라우저에서 UI가 겹치거나 보이지 않습니다.
진단: CSS 검증, 컨테이너/그리드 기준 확인, 접근성 대비 점검.
경고: 사용성 저하
증상: 키보드 포커스 이동 불가, 스크린 리더 읽기 오류.
진단: 포커스 순서, ARIA 라벨, 이름/역할/값 검사.
개선 시 UX 큰 폭 향상
alt를 제공합니다.label은 for로 컨트롤과 연결하고 에러 메시지에 aria-live를 사용합니다.overflow와 position을 점검합니다.min-width)와 축 정렬을 확인합니다.clamp(), minmax()로 급격한 변형을 줄입니다.내용
내용
내용
// 위험: null 요소에 접근
// const node = document.querySelector('.target').textContent;
// 안전: 존재 확인 후 접근
const node = document.querySelector('.target');
if (node) {
node.textContent = '준비 완료';
} else {
console.warn('요소(.target)를 찾을 수 없습니다.');
}
async function fetchWithRetry(url, opts = {}, { retries = 3, backoff = 500 } = {}) {
let lastErr;
for (let i = 0; i < retries; i++) {
try {
const res = await fetch(url, opts);
if (!res.ok) throw new Error('HTTP ' + res.status);
return res;
} catch (err) {
lastErr = err;
await new Promise(r => setTimeout(r, backoff * (i + 1)));
}
}
throw lastErr;
}
Access-Control-Allow-Origin 헤더 설정 확인.
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600
title, meta description을 최적화합니다.robots.txt와 sitemap.xml을 제공하고 오류 페이지는 올바른 상태코드를 사용합니다.button, a 등 기본 요소를 우선 사용합니다.aria-live를 적용합니다.탭 순서는 DOM 순서를 따르며, 숨김 요소는 포커스가 가지 않도록 합니다.
lang 속성을 정확히 설정해 발음/읽기 품질을 향상합니다.preload, prefetch를 적절히 사용합니다.srcset, sizes, loading="lazy".
requestAnimationFrame 또는 debounce.
Content-Security-Policy: default-src 'self'; img-src 'self' https:; script-src 'self'; style-src 'self'; connect-src 'self' https:;
| 항목 | 설명 | 상태 |
|---|---|---|
| HTML 유효성 | 중복 ID, 닫힘 태그, 속성 값 검증 | 완료 |
| 접근성 | 키보드 내비, 대체 텍스트, 대비 | 점검 |
| 네트워크 | 상태코드, CORS, 타임아웃 | 완료 |
| 성능 | LCP/CLS/INP 기준 만족 | 점검 |
| 보안 | CSP, XSS/CSRF 방지, 비밀관리 | 완료 |
<main role="main">
<section aria-labelledby="error-title">
<h1 id="error-title">요청하신 페이지를 찾을 수 없습니다 (404)</h1>
<p>주소를 확인하거나 <a href="/">홈으로 이동</a>하세요.</p>
</section>
</main>
self.addEventListener('fetch', (event) => {
event.respondWith((async () => {
try {
const network = await fetch(event.request);
return network;
} catch {
const cache = await caches.match(event.request);
return cache || new Response('오프라인입니다.', { status: 503 });
}
})());
});
{
"timestamp": "2025-10-26T21:25:00+09:00",
"level": "error",
"message": "API 응답 실패",
"errorId": "e-20251026-001",
"context": {
"route": "/checkout",
"userAgent": "Mozilla/5.0",
"locale": "ko-KR"
}
}