HTTP 리다이렉트
==========

URL 리다이렉션 혹은 URL 포워딩은 페이지 단위의 실제 리소스, 폼 혹은 전체 웹 애플리케이션이 다른 URL에 위치하고 있는 상태에서 링크를 존속시키는 기술입니다. HTTP는 많은 목표를 위해 사용되는 이런 동작을 수행하기 위해 특별한 종류의 응답인 *HTTP 리다이렉트*를 제공합니다: 사이트 유지관리가 진행 중인 상태에서의 일시적인 리다이렉션, 사이트 아키텍쳐의 변경 이후에도 외부 링크를 동작하는 상태로 유지시키기 위한 영구적인 리다이렉션, 파일 업로드 시 진행 상태 페이지 그리고 그 외의 수많은 리다이렉션들 ...

원칙
--

HTTP에서, 리다이렉션은 요청에 대해 특별한 응답(*리다이렉트*)을 전송함으로써 촉발됩니다. HTTP 리다이렉트는 `3xx` 상태 코드를 지닌 응답입니다. 리다이렉트 응답을 수신한 브라우저는, 제공된 새로운 URL을 사용하며 그것을 즉시 로드합니다: 대부분의 경우, 리다이렉션은 사용자에게는 보이지 않는데다가, 적은 성능 저하를 일으킵니다.

![](/ko/docs/Web/HTTP/Redirections/httpredirect.png)

리다이렉트에는 몇 가지 유형이 있으며 세 가지 카테고리로 나누어집니다: 영속적, 일시적 그리고 특수 리다이렉션.

### 영속적인 리다이렉션

이 리다이렉션은 영원히 지속됨을 의미합니다. 원래의 URL이 더 이상 사용되지 않아야 하며 새로운 URL을 더 선호해야 함을 시사합니다. 검색 엔진 로봇은 그들의 인덱스 내에서 리소스에 대한 연관 URL의 갱신을 촉발시킵니다.

| 코드 | 텍스트 | 메서드 핸들링 | 일반적인 유스케이스 |
| --- | --- | --- | --- |
| `301` | `Moved Permanently` | `GET` 메서드는 변경되지 않습니다. 다른 메서드들은 `GET`로 변하거나 변하지 않을수도 있습니다.[1] | 웹 사이트의 재편성. |
| `308` | `Permanent Redirect` | 메서드와 본문은 변하지 않습니다. | GET이 아닌 링크/동작을 지닌, 웹 사이트의 재편성. |

[1] 명세는 메서드 변경을 허용할 의도가 없으나, 사실 상 사용자 에이전트들이 그렇게 하고 있습니다. `308` 은 `GET`이 아닌 메서드를 사용할 때 동작의 애매모호함을 제거하고자 만들어졌습니다.

### 일시적인 리다이렉션

때때로 요청된 리소스는 그것의 표준 위치에서 접근할 수 없고 다른 위치에서 접근 가능한 경우가 있습니다. 이런 경우 일시적인 리다이렉트가 사용될 수 있습니다. 검색 엔진 로봇은 새로운, 일시적인 링크를 기억하지 못합니다. 일시적인 리다이렉션은 일시적인 진행율 페이지를 표시하고자 리소스를 만들고 갱신하며 삭제할 때 사용될 수 도 있습니다.

| 코드 | 텍스트 | 메서드 핸들링 | 일반적인 유스 케이스 |
| --- | --- | --- | --- |
| `302` | `Found` | `GET` 메서드는 변경되지 않습니다. 다른 메서드들은 `GET`로 변하거나 변하지 않을수도 있습니다.[2] | 웹 페이지가 예측하지 못한 이유로 일시적으로 이용 불가능할 때 가 있습니다. 그런 이유로, 검색 엔진은 그들의 링크를 갱신하지 않습니다. |
| `303` | `See Other` | `GET` 메서드는 변경되지 않습니다. 다른 메서들은 `GET` 메서드로 *변경됩니다*(본문을 잃게 됩니다). | 동작을 다시 촉발시키는 페이지 리프레시를 막기 위해 `PUT` 혹은 `POST` 뒤에 사용됩니다. |
| `307` | `Temporary Redirect` | 메서드와 본문은 변경되지 않습니다. | 웹 페이지가 예측하지 못한 이유로 일시적으로 이용 불가능할 때 가 있습니다. 그런 이유로, 검색 엔진은 그들의 링크를 갱신하지 않습니다. GET이 아닌 링크/동작이 사이트에서 이용 가능할 때 `302`보다 더 좋습니다. |

[2] 명세에는 메서드 변경을 허용할 의도가 없으나, 실질적으로 사용자 에이전트들이 그렇게 하고 있습니다. `307` 은 `GET`이 아닌 메서드들을 사용하는 경우 동작의 애매모호함을 제거하기 위해 만들어집니다.

### 특수 리다이렉션

이런 보통 리다이렉션과 더불어, 특별한 두 가지 리다이렉션이 더 있습니다. `304` (수정되지 않음)은 (오랜된)로컬에 캐시된 복사본으로 페이지를 리다이렉트시키며, `300` (다중 선택)은 수동 리다이렉션입니다:브라우저에 의해 웹 페이지로 표현되는 분문은 가능한 리다이렉션을 나열하며 사용자는 그 중 하나를 선택하기 위해 클릭합니다.

| 코드 | 텍스트 | 일반적인 유스케이스 |
| --- | --- | --- |
| `300` | `Multiple Choice` | 이런 경우가 많지는 않습니다: 본문의 HTML 페이지 내에 선택지가 나열됩니다. `200` `OK` 상태와 함께 서브될 수 있습니다. |
| `304` | `Not Modified` | 캐시 리프레시: 캐시 값이 여전히 사용 가능할 정도로 신선함을 가리킵니다. |

리다이렉션을 명시하는 대체 방법
-----------------

HTTP 리다이렉트가 리다이렉션을 정의하는 유일한 방법은 아닙니다. 두 개의 다른 방법이 존재합니다: `<meta>` 엘리먼트를 사용하는 HTML 리다이렉션과 DOM을 사용하는 JavaScript 리다이렉션이 있습니다.

### HTML 리다이렉션

HTTP 리다이렉트는 리다이렉션을 만드는 가장 좋은 방법이지만, 때때로 웹 개발자는 서버에 대한 제어권을 가지고 있지 않거나 그것을 구성할 수 없는 경우가 있습니다. 이런 특수한 상황들 때문에, 웹 개발자들은 `refresh`를 설정하기 위해 페이지의 `<head>` 내에 `<meta>` 엘리먼트와 `http-equiv` 속성으로 HTML 페이지를 만들 수 있습니다. 해당 페이지를 디스플레이할 때, 브라우저는 이 엘리먼트를 발견하고 표시된 페이지로 이동할 것입니다.


```html
<head>
  <meta http-equiv="refresh" content="0;URL='http://www.example.com/'" />
</head>
```


`content` 속성은 주어진 URL로 리다이렉트 하기 이전에 브라우저가 얼마만큼의 시간(초)을 기다려야 하는지를 나타내는 숫자로 시작됩니다. 더 나은 접근성을 위해 항상 0으로 설정하시기 바랍니다.

두 말할 필요없이, 이 메서드는 HTML 페이지(혹은 그와 유사한 무언가)에서만 동작하며 이미지나 다른 어떤 종류의 컨텐츠에 대해서 사용될 수 없습니다.

**참고:** 이런 리다이렉션들이 브라우저에서 뒤로 가기 버튼을 무용지물로 만든다는 것을 기억하시기 바랍니다: 해당 헤더가 있는 페이지로 다시 돌아갈 수 있는지만 즉시 앞으로 이동하게 될겁니다.

### JavaScript 리다이렉션

JavaScript 내에서의 리다이렉션은 `window.location` (en-US) 프로퍼티에 값을 설정해서 만들어지며 새로운 페이지가 로드됩니다.


```js
window.location = "http://www.example.com/";
```


HTML 리다이렉션처럼, 모든 리소스에서 동작하는 것은 아니며, 명백하게 JavaScript를 실행한 클라이언트 상에서만 동작합니다. 하지만 다른점은, 예를 들어 어떤 조건이 충족되는 경우에만 리다이렉션을 촉발시킬 수 있다는 점에서 더 많은 가능성을 가지고 있습니다.

### 우선 순위

URL 리다이렉션에 대한 세 가지 가능성이 있기에, 몇 가지 방법이 동시에 지정될 수 있는데, 어떤 것이 먼저 적용될까요? 우선 순위는 다음과 같습니다:

1. 페이지가 읽힌 적도 없고 전송된 적도 없는 경우, HTTP 리다이렉트가 항상 먼저 실행됩니다.
2. 어떤 HTTP 리다이렉트로 없는 경우에, HTML 리다이렉트 (`<meta>`)가 실행됩니다.
3. JavaScript 리다이렉트는 최후의 수단으로써 사용되며, 클라이언트 측에서 JavaScript를 활성화시킨 경우에만 사용할 수 있습니다.

가능한 경우, 항상 HTTP 리다이렉트를 사용해야 하며, `<meta>` 엘리먼트를 사용해서는 안됩니다. 만약 개발자가 HTTP 리다이렉트를 변경하고 HTML 리다이렉트를 잊는다면, 리다이렉트는 더 이상 동일한 한 것이 아니거나, 무한 루프로 종료되거나 다른 악몽이 시작될 수도 있습니다.

유스 케이스
------

리다이렉트에 대한 많은 유스 케이스들이 존재하지만, 모든 리다이렉트들이 성능과 직결되므로, 리다이렉트의 사용은 최소한으로 유지되어야 합니다.

### 도메인 앨리어싱

이상적으로, 하나의 로케이션이 존재하고, 그래서 하나의 리소스에 대해 하나의 URL이 존재한다고 가정하겠습니다. 그러나 하나의 리소스에 대한 대체 이름을 갖고자 할 때가 있을 수 있습니다 (www 접두사를 갖거나 갖지 않는 몇몇 도메인 혹은 URL을 더 짧고 기억하기 쉽도록하는 등...). 이런 경우, 리소스를 복제하기 보다는 실제 (정식) URL에 대한 리다이렉트를 사용하는 것이 더 유용합니다.

도메인 앨리어싱을 하는 경우는 다음과 같습니다.

* 사이트 범위 확장. 당신의 사이트가 `www.example.com` 도메인을 가지고 있을 때 `example.com`을 통한 접근도 가능한 경우가 가장 흔한 경우입니다. `example.com` 페이지를 `www.example.com` 로 리다이렉션하는 것이 이 경우에 해당됩니다. 일반적으로 사용되는 별칭 혹은, 도메인 이름에 빈번히 일어나는 오자를 제공할 수도 있습니다.
* 다른 도메인으로의 이동. 예를 들어, 당신의 회사가 이름을 변경했고 이전 이름으로 검색하는 경우 여전히 회사의 옛날 이름으로 웹 사이트를 사용하는 사람들이 새로운 이름의 사이트를 이용하길 바라는 경우에 해당됩니다.
* HTTPS 강제. 사이트에 대한 HTTP 버전 요청은 사이트의 HTTPS 버전으로 리다이렉트될 것입니다.
### 링크 유지하기

웹 사이트를 다시 만들때, 리소스의 URL이 변경되기 마련입니다. 새로운 네이밍 계획과 일치하도록 웹 사이트의 내부 링크를 갱신할 수 있는 경우조차도, 외부 리소스에 의해 사용되는 URL에 대해서는 어쩔 수가 없습니다. 그들은 당신에게 소중한 사용자이므로(또 SEO에 도움이 되길 바라는 마음으로) 해당 링크를 깨뜨리고 싶지 않을 것이기에, 이전 URL에서 새로운 URL로의 리다이렉트를 설정하려 할 겁니다.

**참고:** 이 기술 또한 내부 링크에 대해서 동작하므로, 내부 리다이렉트는 피해야 할 겁니다. 리다이렉트는 상당한 성능 비용이 드므로(추가적인 HTTP 요청이 수행되므로) 내부 링크를 바로잡아 내부 다이렉트를 피할 수 있다면 해당 링크를 수정해야 합니다.

### 안전하지 않은 요청에 대한 일시적인 응답

Unsafe 요청이 서버의 상태를 수정할 경우, 사용자가 이를 우연히 재연할 수 있어서는 안됩니다. 일반적으로, 당신은 사용자가 `PUT`, `POST` 혹은 `DELETE` 요청을 재전송하기를 바라지는 않을 겁니다. 만약 당신이 해당 요청의 결과로 지금 막 응답을 전송했다면, 단순히 새로고침 버전을 누르는 것만으로 요청은 재전송될 겁니다(아마도 확인 메시지 이후에).

이런 경우, 서버는 올바른 정보를 포함하게 될 `303` (See Other) 요청을 회신할 수 있는데, 새로 고침 버튼이 눌린 경우, 안전하지 않은 요청이 재연되지 않고 동일한 페이지가 다시 디스플레이될 것입니다.

### 긴 요청에 대한 일시적인 응답

어떤 요청들은 때때로 후처리를 위해 예정되는 `DELETE` 요청처럼, 서버 상에서 좀 더 많은 시간을 필요로 하는 경우가 있습니다. 이와 같은 경우에, 응답은 `303` (See Other) 리다이렉트로, 어떤 동작이 예정되어 있고 진행률에 관해 알려주고 그 동작을 취소할 수 있도록 해주는 페이지로 리다이렉트됩니다.

일반 서버 내 리다이렉트 구성
----------------

### Apache

리다이렉트는 서버 구성 파일 혹은 각 디렉토리의 `.htaccess` 내에서 설정될 수 있습니다.

mod\_alias 모듈은 (기본값으로) `302` 응답을 설정하는 `Redirect` 그리고 `Redirect_Match` 디렉티브를 가지고 있습니다:
```

<VirtualHost *:80>
  ServerName example.com
  Redirect / http://www.example.com
</VirtualHost>
```


URL `http://example.com/` 은 `http://www.example.com/` 로 리다이렉트됩니다(하지만 `http://example.com/other.html`은 리다이렉트되지 않습니다).

`Redirect_Match` 도 똑같이 동작하지만 영향을 받은 URL 컬렉션 정의를 위해 정규 표현식을 받습니다:
```

RedirectMatch ^/images/(.*)$ http://images.example.com/$1
```


`images/` 폴더 내 모든 문서들은 다른 도메인으로 리다이렉트될 것입니다.

일시적인 리다이렉트를 설정하고 싶지 않다면, 다른 리다이렉트를 설정하는데 여분의 파라메터(사용하고자 하는 HTTP 상태 코드 혹은 `permanent` 키워드)를 사용할 수 있습니다:
```

Redirect permanent / http://www.example.com
Redirect 301 / http://www.example.com
```


mod\_rewrite 모듈도 리다이렉트를 만드는데 사용될 수 있습니다. 이것은 약간 더 복잡한데, 사용은 약간 더 복잡합니다.

### Nginx

Nginx에서는, 당신이 리다이렉트하고자 하는 컨텐츠에 대한 특정 서버 블록을 만들 수 있습니다:
```

server {
  listen 80;
  server_name example.com;
  return 301 $scheme://www.example.com$request_uri;
}
```


폴더 혹은 페이지의 하위 집합에만 적용되는 리다이렉트를 원한다면, `rewrite` 디렉티브를 사용하시기 바랍니다:
```

rewrite ^/images/(.*)$ http://images.example.com/$1 redirect;
rewrite ^/images/(.*)$ http://images.example.com/$1 permanent;
```

### IIS

IIS에서는, 리다이렉션 구성을 위해 `<httpRedirect>` 요소를 사용할 수 있습니다.

리다이렉션 루프
--------

리다이렉션 루프는 성공적인 리다이렉션이 이전의 리다이렉션을 다시 따라갈 때 일어납니다. 다시 말해, 결코 끝나지 않으면, 끝까지 어떤 페이지도 볼 수 없는 루프가 존재한다는 말입니다.

대부분의 경우, 이런 문제는 서버 측 문제이며 서버가 이를 감지할 수 없다면, `500` `Internal Server Error`를 회신할 것입니다. 서버 구성을 수정한 직후에 그런 오류를 보게 된다면, 그것은 리다이렉션 루프일 가능성이 큽니다.

때로는, 서버가 그것을 감지하지 않을 때도 있을 겁니다: 전체적인 그림을 모르는 몇 개의 서버에 리다이렉션 루프가 행해지기 때문입니다. 이런 경우, 브라우저가 이를 감지하고 오류 메시지를 보여줄 것입니다. Firefox는 다음과 같이 디스플레이하게 됩니다:
```

Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
```

반면, 크롬은 다음과 같이 디스플레이합니다:
```

This Webpage has a redirect loop
```


모든 경우에, 사용자가 할 수 있는 일은 그리 많지 않습니다(사용자 측에서 캐시 혹은 쿠키의 불일치와 같은 어떤 변화를 주지 않은 이상말이죠).

리다이렉션 루프는 사용자 경험을 완전히 망쳐놓기에 리다이렉션 루프를 피하는 것은 대단히 중요합니다.