Meta Refresh와 JavaScript 리다이렉트 가이드
서버 측 리다이렉트(301/302)가 항상 첫 번째 선택입니다. 하지만 서버 설정을 변경할 수 없거나 런타임 조건에 따라 리다이렉트해야 하는 경우, 클라이언트 측 리다이렉트가 유용합니다.
HTML meta refresh
<!-- 즉시 리다이렉트 -->
<meta http-equiv="refresh" content="0; url=/new-page.html">
<!-- 3초 후 리다이렉트 -->
<meta http-equiv="refresh" content="3; url=https://newdomain.com">
- ✅ JavaScript 없이 동작
- ✅ HTML 한 줄로 구현 가능
- ❌ 페이지 로드 후 취소 불가
- ❌ 뒤로 가기 버튼 트랩 생성 (뒤로 가면 다시 리다이렉트됨)
- ❌ SEO에 불리 — Google이 권장하지 않음
⚠️ 뒤로 가기 버튼 트랩
Meta refresh는 리다이렉트 전에 현재 페이지를 브라우저 히스토리에 추가합니다. 사용자가 "뒤로"를 누르면 리다이렉트 페이지로 돌아가 다시 전송됩니다. 가능한 한 이 패턴을 피하세요.
JavaScript 리다이렉트 메서드
window.location.href (가장 일반적)
// 현재 페이지를 히스토리에 추가 — 사용자가 뒤로 갈 수 있음
window.location.href = 'https://example.com';
location.replace() (히스토리 항목 없음)
// 현재 히스토리 항목을 대체 — 사용자가 뒤로 갈 수 없음
location.replace('https://example.com');
location.assign() (href와 동일)
location.assign('https://example.com');
window.open() (새 탭)
window.open('https://example.com', '_blank');
주요 차이점
히스토리 항목
- 히스토리에 추가:
location.href,location.assign(), meta refresh - 히스토리에 추가하지 않음:
location.replace()
취소 가능 여부
- 취소 가능: JavaScript (
clearTimeout사용) - 취소 불가: meta refresh
사용 시기 가이드
meta refresh를 사용하는 경우
- JavaScript가 없는 정적 HTML 페이지
- 카운트다운이 있는 "페이지가 이동했습니다" 알림
location.href를 사용하는 경우
- 조건부 리다이렉트 로직이 필요
- 사용자가 뒤로 갈 수 있게 하고 싶음
if (!user.isLoggedIn) {
location.href = '/login';
}
location.replace()를 사용하는 경우
- 로그인 후 — 사용자를 로그인 페이지로 돌려보내지 않음
- 오류 페이지 자동 리다이렉트
- 모바일/데스크톱 감지 리다이렉트
if (/Android|iPhone/i.test(navigator.userAgent)) {
location.replace('/mobile/');
}
SEO 영향
- Meta refresh — Google이 공식적으로 권장하지 않으며, 랭킹 하락의 원인이 될 수 있음
- JavaScript 리다이렉트 — Google이 따라갈 수 있지만, 서버 측 리다이렉트보다 처리가 느림
- 둘 다 HTTP 상태 코드를 갖지 않음 — 검색 엔진이 이동이 영구적인지 임시적인지 판단 불가
🚨 중요
영구적인 URL 변경에는 반드시 서버 측 301 리다이렉트를 사용하세요. 클라이언트 측 리다이렉트는 동적인 런타임 시나리오에만 사용합니다.
흔한 실수
리다이렉트 후 코드가 계속 실행됨
// ❌ 아래 코드도 실행됨
if (needRedirect) { location.href = '/other'; }
doSomethingElse(); // 여전히 실행됨!
// ✅ return 사용
if (needRedirect) { location.href = '/other'; return; }
doSomethingElse();
모바일 리다이렉트 루프
// ✅ 재리다이렉트 방지 가드
if (isMobile && !location.pathname.startsWith('/mobile/')) {
location.replace('/mobile' + location.pathname);
}
쿼리 문자열 손실
// ❌ 쿼리 문자열이 사라짐
location.href = '/new-page';
// ✅ 쿼리 문자열 유지
location.href = '/new-page' + location.search;