HTTP/Guides/Redirections in HTTP

김동현·2026년 3월 22일

안녕하세요! 이번에는 프론트엔드 개발자라면 반드시 알아야 할 'HTTP 리다이렉션(Redirections)'에 대해 알아보겠습니다.

사용자가 예전 주소로 접속했을 때 새로운 주소로 자연스럽게 넘겨주거나, 로그인을 하지 않은 사용자가 마이페이지에 접근하려고 할 때 로그인 페이지로 튕겨내는 기능 등 프론트엔드 실무와 아주 밀접하게 맞닿아 있는 주제랍니다. 면접에서도 "301과 302의 차이가 뭐죠?"라는 질문이 심심치 않게 나오니, 이번 기회에 확실히 다져보아요!


HTTP 리다이렉션 (Redirections in HTTP)

URL 포워딩(URL forwarding)이라고도 불리는 URL 리다이렉션(URL redirection)은 하나의 페이지, 폼, 전체 웹사이트 또는 웹 애플리케이션에 두 개 이상의 URL 주소를 부여할 수 있게 해주는 기술입니다. HTTP는 이 작업을 위해 HTTP 리다이렉트(HTTP redirect)라는 특별한 종류의 응답을 가지고 있어요.

리다이렉트는 다음과 같은 수많은 목표를 달성하는 데 사용됩니다:

  • 사이트 유지보수나 서버 다운타임 동안의 임시 리다이렉션
  • 사이트의 URL을 변경한 후에도 기존 링크나 즐겨찾기가 끊기지 않도록 유지하기 위한 영구 리다이렉션
  • 파일을 업로드할 때의 진행 상태 페이지 등

원리 (Principle)

HTTP에서 리다이렉션은 서버가 요청에 대해 특별한 리다이렉트 응답을 보냄으로써 트리거(발동)됩니다. 리다이렉트 응답은 3으로 시작하는 상태 코드(status codes)를 가지며, 어디로 리다이렉트할지 새로운 URL을 담고 있는 Location 헤더를 포함하고 있어요.

브라우저가 리다이렉트 응답을 받으면, 즉시 Location 헤더에 제공된 새로운 URL을 로드합니다. 추가적인 왕복 통신(round-trip)으로 인해 아주 약간의 성능 저하가 있긴 하지만, 사용자는 리다이렉션이 일어났다는 사실을 거의 눈치채지 못하죠.

클라이언트에서 서버로의 요청과 301 이동 응답, 그리고 새 URL로의 GET 요청 흐름

리다이렉트에는 여러 종류가 있는데, 크게 세 가지 카테고리로 나눌 수 있습니다:

  1. 영구 리다이렉션 (Permanent redirections)
  2. 임시 리다이렉션 (Temporary redirections)
  3. 특수 리다이렉션 (Special redirections)

영구 리다이렉션 (Permanent redirections)

이 리다이렉션은 영원히 지속될 것임을 의미합니다. 기존의 원래 URL은 더 이상 사용되지 않아야 하며, 새로운 URL로 대체되어야 한다는 것을 내포하고 있죠. 검색 엔진 로봇(크롤러), RSS 리더기, 그리고 기타 크롤러들은 해당 리소스에 대한 원래 URL을 이 새로운 URL로 아예 업데이트해 버립니다.

💡 강사의 팁: 프론트엔드/백엔드 기술 면접 단골 질문입니다! "301 리다이렉트가 뭔가요? SEO(검색엔진 최적화)에 어떤 영향을 주나요?"라는 질문을 받으면, "영구 이동을 의미하며, 구글 같은 검색 엔진이 기존 페이지의 검색 랭킹 점수를 새로운 URL로 고스란히 넘겨주기 때문에 SEO에 매우 중요합니다!"라고 답변하시면 완벽합니다.

코드텍스트메서드 처리 (Method handling)전형적인 사용 사례
301Moved PermanentlyGET 메서드는 변경되지 않습니다. 다른 메서드들은 GET으로 변경될 수도 있고 아닐 수도 있습니다. [1]웹사이트 구조 개편 (Reorganization).
308Permanent Redirect메서드와 본문(body)이 변경되지 않습니다.비-GET(non-GET) 링크나 작업이 포함된 웹사이트 구조 개편.

[1] 원래 HTTP 명세에서는 리다이렉트 시 메서드를 변경하는 것을 허용할 의도가 없었습니다. 하지만 마음대로 메서드를 바꿔버리는(예: POST로 보냈는데 GET으로 리다이렉트) 기존의 사용자 에이전트(브라우저)들이 존재했죠. 그래서 비-GET(non-GET) 메서드를 사용할 때 동작의 모호함을 없애기 위해 308 코드가 새롭게 만들어졌습니다.


임시 리다이렉션 (Temporary redirections)

때로는 요청한 리소스를 공식적인 원래 위치에서 접근할 수 없지만, 임시로 다른 곳에서 접근해야 할 때가 있습니다. 이럴 때 임시 리다이렉트를 사용합니다.

검색 엔진 로봇이나 크롤러들은 이 새롭고 '임시적인' URL을 기억(저장)하지 않아요. 임시 리다이렉션은 리소스를 생성, 업데이트, 또는 삭제할 때 진행 상황을 보여주는 임시 페이지를 표시하기 위해서도 사용됩니다.

코드텍스트메서드 처리 (Method handling)전형적인 사용 사례
302FoundGET 메서드는 변경되지 않습니다. 다른 메서드들은 GET으로 변경될 수도 있고 아닐 수도 있습니다. [2]예기치 못한 이유로 웹 페이지를 임시로 사용할 수 없을 때.
303See OtherGET 메서드는 변경되지 않습니다. 다른 메서드들은 GET으로 변경됩니다 (본문 데이터가 유실됨).PUT이나 POST 요청 후에 리다이렉트할 때 주로 쓰입니다. 결과 페이지를 새로고침하더라도 이전 작업(예: 결제, 글쓰기 등)이 중복해서 다시 실행되지 않도록 하기 위함이죠.
307Temporary Redirect메서드와 본문(body)이 변경되지 않습니다.예기치 못한 이유로 웹 페이지를 임시로 사용할 수 없을 때. 사이트 내에 비-GET 작업(POST 등)이 존재할 경우 302보다 훨씬 안전하고 좋습니다.

[2] 앞서 301에서 설명한 것과 마찬가지로, 명세와 다르게 브라우저들이 임의로 메서드를 변경하는 것을 막기 위해 명확한 임시 리다이렉트 코드인 307이 만들어졌습니다.


특수 리다이렉션 (Special redirections)

304 (Not Modified)는 페이지를 (만료되었다고 생각했던) 로컬에 캐시된 복사본으로 리다이렉트 시키는 역할을 합니다. 그리고 300 (Multiple Choices)는 수동 리다이렉션이에요. 브라우저가 웹 페이지 형태로 본문(body)을 표시하면, 거기에 가능한 리다이렉트 대상들의 목록이 뜨고 사용자가 직접 하나를 클릭해서 선택하는 방식이죠.

코드텍스트전형적인 사용 사례
300Multiple Choices흔하게 쓰이진 않습니다. 선택지들이 본문(body) 안의 HTML 페이지에 나열됩니다. 기계가 읽을 수 있는 선택지들은 rel=alternate를 가진 Link 헤더 형태로 보내는 것이 권장됩니다.
304Not Modified캐시 재검증(revalidation)을 위한 조건부 요청에 대해 전송됩니다. 캐시된 응답이 여전히 신선(fresh)해서 그대로 사용해도 됨을 나타냅니다.

💡 강사의 팁: 이전 시간에 배웠던 캐싱(Caching) 내용이 여기서 또 나오네요! 304 Not Modified는 실제로 데이터를 다시 내려받는 게 아니라 "너 브라우저 캐시에 있는 거 최신 버전 맞으니까 그거 그대로 써!"라고 '자체 캐시로 리다이렉트' 시키는 특별한 상태 코드라고 이해하시면 좋습니다.


리다이렉션을 지정하는 대안적인 방법들 (Alternative way of specifying redirections)

HTTP 리다이렉트 응답만이 리다이렉션을 만드는 유일한 방법은 아니에요. 두 가지 다른 방법이 더 있습니다:
1. HTML의 <meta> 요소를 이용한 HTML 리다이렉션
2. DOM을 이용한 JavaScript 리다이렉션


HTML 리다이렉션 (HTML redirections)

HTTP 리다이렉트가 리다이렉션을 만드는 가장 좋은 방법이지만, 때로는 웹 서버의 설정(HTTP 헤더)을 직접 제어할 수 없는 상황이 있을 수 있습니다. 그럴 때는 페이지의 <head> 태그 안에 http-equiv 속성을 Refresh로 설정한 <meta> 요소를 넣어보세요. 페이지가 화면에 표시될 때, 브라우저가 지정된 URL로 알아서 이동합니다.

<head>
  <meta http-equiv="Refresh" content="0; URL=[https://example.com/](https://example.com/)" />
</head>

content 속성은 가장 먼저 '숫자'로 시작해야 하는데, 이는 지정된 URL로 리다이렉트하기 전에 브라우저가 몇 초 동안 대기할지를 나타냅니다. 웹 접근성(accessibility) 준수를 위해 이 숫자는 항상 0으로 설정하는 것이 좋습니다.

당연하게도 이 방법은 HTML에서만 동작하며, 이미지나 다른 형태의 콘텐츠에는 사용할 수 없습니다.


JavaScript 리다이렉션 (JavaScript redirections)

JavaScript에서의 리다이렉션은 window.location 속성에 새로운 URL 문자열을 할당함으로써 수행되며, 이로 인해 새로운 페이지가 로드됩니다.

window.location = "[https://example.com/](https://example.com/)";

💡 강사의 팁: 프론트엔드 개발 시 바닐라 JS에서는 이 방법을 많이 쓰지만, React(React Router)나 Next.js 같은 프레임워크를 쓸 때는 useNavigate('/path')router.push('/path')를 쓰는 것이 더 흔하죠? 하지만 브라우저 레벨에서 근본적으로 지원하는 자바스크립트 리다이렉트는 바로 이 window.location.href (또는 window.location.replace())라는 점을 잊지 마세요!

HTML 리다이렉트처럼 이 방법도 모든 리소스에 동작하는 것은 아니며, 당연히 JavaScript를 실행할 수 있는 클라이언트(브라우저)에서만 동작합니다. 하지만 대신 더 많은 가능성을 제공해 주죠. 예를 들어, 특정 조건(로그인 여부 등)이 충족될 때만 리다이렉트를 트리거하도록 코드를 짤 수 있습니다.


우선순위 (Order of precedence)

리다이렉트를 트리거하는 방법이 세 가지나 있다 보니, 이 방법들이 동시에 사용될 수도 있습니다. 그럼 과연 어떤 것이 가장 먼저 적용될까요?

  1. HTTP 리다이렉트가 항상 가장 먼저 실행됩니다 — 애초에 페이지 파일(HTML 등)이 전송되기도 전에 헤더 단에서 일어나기 때문이죠.
  2. 약간 놀랍게도, HTML 리다이렉트보다 JavaScript 리다이렉트가 먼저 실행됩니다. 왜냐하면 <meta> 태그를 이용한 리다이렉트는 페이지가 완전히 로드(completely loaded)된 후에 발생하는데, 이는 스크립트들이 모두 실행되고 난 이후이기 때문입니다.
  3. HTML 리다이렉트 (<meta>)는 페이지가 로드되기 전에 아무런 HTTP 리다이렉트나 JavaScript 리다이렉트가 실행되지 않았을 때 비로소 실행됩니다.
  4. 페이지가 로드된 '이후'에 발생하는 JavaScript 리다이렉트(예: 버튼 클릭 이벤트 등)가 있다면, 앞선 방법들에 의해 페이지가 이미 리다이렉트되지 않았을 경우에만 맨 마지막에 실행됩니다.

가능하다면 항상 HTTP 리다이렉트를 사용하시고, <meta> 요소 리다이렉트를 추가하지 마세요. 누군가가 HTTP 리다이렉트를 수정해놓고 HTML 리다이렉트 쪽은 까먹고 수정하지 않는다면, 두 리다이렉트 규칙이 서로 달라지게 되어 무한 루프(infinite loop)나 다른 악몽 같은 버그를 유발할 수 있습니다.


사용 사례 (Use cases)

리다이렉트를 활용하는 사례는 무수히 많지만, 리다이렉트가 발생할 때마다 성능에 영향을 미치기 때문에(추가 통신 발생) 꼭 필요한 경우에만 최소한으로 사용해야 합니다.

도메인 별칭 (Domain aliasing)

이상적으로는 각 리소스당 하나의 위치, 즉 하나의 URL만 존재하는 것이 맞습니다. 하지만 리소스에 대한 대안적인 이름(주소)이 필요한 이유들이 있죠:

사이트 접근성 확장 (Expanding the reach of your site)
: 가장 흔한 경우는 사이트의 메인 주소가 www.example.com인데, 사용자가 그냥 example.com을 입력해도 접속되도록 만들어야 할 때입니다. 이를 위해 example.com에서 www.example.com으로 가는 리다이렉션을 설정하게 되죠. 도메인의 흔한 동의어나 자주 발생하는 오타(typo)에 대해서도 리다이렉트를 설정할 수 있습니다.

새 도메인으로의 이동 (Moving to a new domain)
: 예를 들어 회사의 이름이 바뀌어서 도메인을 변경했지만, 기존 사용자들이 예전 링크나 즐겨찾기를 눌렀을 때 새 이름의 도메인으로 잘 찾아오게 만들고 싶을 때 쓰입니다.

HTTPS 강제 (Forcing HTTPS)
: 보안이 적용되지 않은 http:// 버전의 사이트로 들어오는 요청을, 보안이 적용된 https:// 버전으로 리다이렉트 시킬 때 사용됩니다.

웹사이트 구조를 개편하게 되면 내부 URL들이 바뀌게 됩니다. 내 웹사이트 안의 내부 링크들은 새 URL에 맞게 직접 수정할 수 있겠지만, 외부 사이트(다른 블로그나 포럼 등)에서 내 사이트를 참조할 때 쓴 외부 URL들은 내 마음대로 바꿀 수가 없죠.

이런 외부 링크들이 깨지는 것(404 에러)은 원치 않으실 겁니다. 귀중한 방문자들을 데려다주기도 하고 SEO(검색엔진 최적화)에도 도움이 되니까요. 그래서 기존의 예전 URL에서 새로운 URL로 향하는 리다이렉트를 설정하게 됩니다.

참고 (Note):
이 기법은 내부 링크에도 똑같이 동작하긴 하지만, 가급적 '내부' 리다이렉트는 피하는 것이 좋습니다. 리다이렉트는 부가적인 HTTP 요청을 발생시키므로 눈에 띄는 성능 저하 비용을 치르게 됩니다. 만약 내부 링크들을 직접 수정해서 리다이렉트 자체를 피할 수 있다면, 당연히 링크를 직접 고치는 것이 정답입니다.

안전하지 않은 요청에 대한 임시 응답 (Temporary responses to unsafe requests)

안전하지 않은(Unsafe) 요청은 서버의 상태를 변경시키며, 사용자가 실수로 이 요청을 두 번 연속해서 보내는 일은 막아야 합니다.

대표적으로 사용자가 글을 등록하거나 결제를 하는 PUT, POST, DELETE 요청을 다시 전송하게 만들고 싶지 않으실 겁니다. 만약 이 요청에 대한 결과를 단순한 응답 페이지로 바로 뿌려주게 되면, 사용자가 새로고침 버튼(F5)을 눌렀을 때 (경고창이 뜨긴 하겠지만) 해당 요청이 그대로 다시 서버로 전송되어 중복 결제 같은 큰일이 벌어질 수 있습니다.

💡 강사의 팁: 이를 방지하기 위해 사용하는 아주 유명한 디자인 패턴이 바로 PRG (Post/Redirect/Get) 패턴입니다! 서버는 POST 요청을 무사히 처리한 후 결과 페이지를 응답하는 대신, 303 상태 코드로 결과 페이지의 URL을 던져줍니다. 그럼 브라우저가 그 URL로 깔끔하게 GET 요청을 보내게 되고, 이후 사용자가 새로고침을 백 번 눌러도 안전한 GET 요청만 반복될 뿐 폼 데이터가 재전송되지 않게 됩니다.

이 경우 서버는 올바른 정보를 담고 있는 URL로 향하는 303 (See Other) 응답을 클라이언트에게 보낼 수 있습니다. 이렇게 하면 새로고침 버튼을 누르더라도 안전하지 않은 요청이 다시 반복되는 일 없이 해당 페이지의 화면만 다시 그려지게 됩니다.

처리가 오래 걸리는 요청에 대한 임시 응답 (Temporary responses to long requests)

나중에 처리하도록 스케줄링된 DELETE 요청처럼, 서버에서 작업하는 데 시간이 꽤 오래 걸리는 요청들이 있습니다. 이 경우에 서버는 응답으로 303 (See Other) 리다이렉트를 보내는데, 이 리다이렉트는 "작업이 잘 예약되었습니다"라고 알려주는 페이지로 향하며, 궁극적으로는 진행 상황을 알려주거나 취소할 수 있는 페이지로 연결됩니다.


일반적인 웹 서버에서의 리다이렉트 설정 (Configuring redirects in common servers)

Apache

리다이렉트는 서버의 주요 설정 파일이나 각 디렉터리의 .htaccess 파일에서 설정할 수 있습니다.

mod_alias 모듈은 기본적으로 302 리다이렉트를 설정하는 RedirectRedirectMatch 지시어(directives)를 제공합니다:

<VirtualHost *:443>
  ServerName example.com
  Redirect / [https://www.example.com](https://www.example.com)
</VirtualHost>

이렇게 하면 https://example.com/ URL은 https://www.example.com/으로 리다이렉트되며, 그 아래에 있는 어떤 파일이나 디렉터리 경로도 그대로 따라갑니다. (예: https://example.com/some-page -> https://www.example.com/some-page)

RedirectMatch도 똑같은 일을 하지만, 영향을 받을 URL들의 패턴을 정의하기 위해 정규 표현식 (regular expression)을 사용할 수 있습니다:

RedirectMatch ^/images/(.*)$ [https://images.example.com/$1](https://images.example.com/$1)

위 코드는 images/ 디렉터리 안에 있는 모든 문서들을 다른 도메인으로 리다이렉트 시킵니다.

임시 리다이렉트(302)를 원하지 않는다면, 추가 파라미터(사용할 HTTP 상태 코드 숫자나 permanent 키워드)를 사용해 다른 리다이렉트를 설정할 수 있습니다:

Redirect permanent / [https://www.example.com](https://www.example.com)
# …다음 코드와 완전히 똑같이 동작합니다:
Redirect 301 / [https://www.example.com](https://www.example.com)

mod_rewrite 모듈을 사용해서 리다이렉트를 만들 수도 있습니다. 이 방법은 훨씬 유연하지만 작성하기가 약간 더 복잡합니다.

Nginx

Nginx에서는 리다이렉트하고 싶은 콘텐츠에 대해 별도의 server 블록을 생성하여 처리합니다:

server {
  listen 80;
  server_name example.com;
  return 301 $scheme://[www.example.com](https://www.example.com)$request_uri;
}

특정 디렉터리나 일부 페이지에만 리다이렉트를 적용하려면 rewrite 지시어를 사용하세요:

rewrite ^/images/(.*)$ [https://images.example.com/$1](https://images.example.com/$1) redirect;
rewrite ^/images/(.*)$ [https://images.example.com/$1](https://images.example.com/$1) permanent;

IIS

Microsoft의 IIS 서버에서는 리다이렉션을 설정하기 위해 <httpRedirect> 요소를 사용합니다.


리다이렉션 루프 (Redirection loops)

리다이렉션 루프(무한 루프)는 이미 쫓아간 리다이렉트 목적지에서 또다시 추가적인 리다이렉트가 꼬리를 물고 이어지면서 발생합니다. 다시 말해, 결코 끝나지 않는 뺑뺑이 루프에 빠져 영원히 페이지를 찾을 수 없게 되는 상태를 말하죠.

대부분의 경우 이는 서버 측의 설정 문제이며, 만약 서버가 이 루프를 스스로 감지할 수 있다면 500 Internal Server Error를 응답으로 돌려보냅니다. 서버 설정을 수정한 직후에 이런 500 에러를 마주했다면 리다이렉션 루프일 가능성이 아주 높습니다.

때로는 여러 대의 서버에 걸쳐서 리다이렉션이 일어나는 바람에, 전체적인 상황을 모르는 개별 서버들이 루프를 감지하지 못하는 경우도 있습니다. 이런 경우에는 클라이언트인 브라우저가 이를 감지하고 에러 메시지를 화면에 띄웁니다.

Firefox의 경우:

Firefox has detected that the server is redirecting the request for this address in a way that will never terminate. (이 주소에 대한 요청이 영구히 끝나지 않을 방식으로 서버에서 리다이렉트 하고 있습니다.)

Chrome의 경우:

This Webpage has a redirect loop (해당 웹페이지에 리디렉션된 횟수가 너무 많습니다 / ERR_TOO_MANY_REDIRECTS)

💡 강사의 팁: 프론트엔드 개발에서도 이 무한 루프를 자주 겪게 됩니다! 대표적으로 Next.js의 middleware.ts에서 로그인하지 않은 유저를 로그인 페이지로 리다이렉트 시켰는데, 그 로그인 페이지조차 보호된 라우트로 인식해서 또 로그인 페이지로 보내버리는 실수를 할 때 브라우저가 이 에러를 뿜어냅니다.

두 경우 모두 캐시나 쿠키의 충돌 등 사용자의 로컬 환경 쪽에 꼬임이 생긴 예외적인 경우가 아니라면 사용자가 직접 해결할 수 있는 방법은 딱히 없습니다.

리다이렉션 루프는 사용자 경험(UX)을 완전히 박살 내버리므로 발생하지 않도록 꼼꼼하게 피하는 것이 매우 중요합니다.


같이 보기 (See also)

profile
프론트에_가까운_풀스택_개발자

0개의 댓글