# HTTP與RESTful
## 11.1 你所沒有深入的HTTP
Internet有兩個核心協議: IP和TCP,這樣講述起來似乎會很漫長。
基本概念
> 超文本傳輸協議 (HTTP-Hypertext transfer protocol) 是一種詳細規定了瀏覽器和萬維網服務器之間互相通信的規則,通過因特網傳送萬維網文檔的數據傳送協議。
* HTTP是用于客戶端與服務端之間的通信。
* 傳輸層的TCP是基于網絡層的IP協議的,而應用層的HTTP協議又是基于傳輸層的TCP協議的。
`注意`: HTTP協議只規定了客戶端與服務端的通信規則,而沒有規定其通訊協議,只是現在的大部分實現都是將TCP作為通訊協議。
### 11.1.1 打開網頁時發生了什么
簡單地來說,當我們在瀏覽器上輸入URL的敲下回車的時候。
* 瀏覽器需要查找域名[^domain](http://www.ituring.com.cn/tupubarticle/%E5%BD%A2%E5%A6%82http://www.phodal.com)的IP,從不同的緩存直至DNS服務器。
* 瀏覽器會給web服務器發送一個HTTP請求
* 服務器“處理”請求
* 服務器發回一個HTML響應
* 瀏覽器渲染HTML到頁面。
在[StackOverflow](http://stackoverflow.com/questions/2092527/what-happens-when-you-type-in-a-url-in-browser)上有一個這樣的回答會比較詳細。
* browser checks cache; if requested object is in cache and is fresh, skip to #9
* browser asks OS for server's IP address
* OS makes a DNS lookup and replies the IP address to the browser
* browser opens a TCP connection to server (this step is much more complex with HTTPS)
* browser sends the HTTP request through TCP connection
* browser receives HTTP response and may close the TCP connection, or reuse it for another request
* browser checks if the response is a redirect (3xx result status codes), authorization request (401), error (4xx and 5xx), etc.; these are handled differently from normal responses (2xx)
* if cacheable, response is stored in cache
* browser decodes response (e.g. if it's gzipped)
* browser determines what to do with response (e.g. is it a HTML page, is it an image, is it a sound clip?)
* browser renders response, or offers a download dialog for unrecognized types
忽略一些細節便剩下了
1. 從瀏覽器輸入URL
2. 瀏覽器找到服務器,服務器返回HTML文檔
3. 從對應的服務器下載資源
說說第一步,開始時我們輸入的是URI(統一資源標識符,Uniform Resource Identifier),它還有另外一個名字叫統一資源定位器(URL[^URL],Uniform Resource Locator)。
### 11.1.2 URL組成
網址算是URL的一個俗稱,讓我們來看看一個URL的組成,以HTTP版IOT中的URL為例。
`http://b.phodal.com/athome/1`
開始之前,我們需要標出URL的80端口以及json文件的全稱,那么上面的網址就會變成
`http://b.phodal.com:80/athome/1.json`
那么對于這個URL的就有下面幾部分組成
* `http://`?http說的是這個URL用的是HTTP協議,至于`//`是一個分隔符,用法和C語言中的`;`一樣。這樣的協議還可以是coap,https,ftp等等。
* `b`?是子域名,一個域名在**允許**的情況下可以有不限數量的子域名。
* `phodal.com`?代表了一個URL是phodal.com下面的域名
* `80`?80是指80端口,默認的都是80,對于一個不是80端口的URL應該是這樣的`http://iot-coap.phodal.com:8896/`
* `athome`?指的是虛擬目錄部分,或者文件路徑
* `1.json`看上去就是一個文件名,然而也代表著這是一個資源。
對就一個稍微復雜點的例子就是
`http://designiot.phodal.com/#你所沒有深入的http`
這里的`#`后面是錨部分,如果你打開這個URL就會發現會直接跳轉到相應的錨部分,對就于下面這樣的一個例子來說
`http://www.phodal.com/search/?q=iot&type=blog`
`?`后面的`q=iot&type=blog`的部分是參數部分,通常用于查詢或者、搜索。
## 11.2 一次HTTP GET請求
當我們打開最小物聯網系統的一個頁面時,如[http://b.phodal.com/athome/1.json](http://b.phodal.com/athome/1.json)
我們在瀏覽器上看到的結果是
~~~
[
{
"id": 1,
"temperature": 19,
"sensors1": 31,
"sensors2": 7.5,
"led1": 0
}
]
~~~
只是我們看到的是結果,忽略了這其中的過程,于是我們用curl[^curl](http://www.ituring.com.cn/tupubarticle/curl%E6%98%AF%E5%88%A9%E7%94%A8URL%E8%AF%AD%E6%B3%95%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%96%B9%E5%BC%8F%E4%B8%8B%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%BC%80%E6%BA%90%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93%E5%B7%A5%E5%85%B7%E3%80%82)命令來看看詳細的情況。
~~~
curl -I -s http://b.phodal.com/athome/1.json
~~~
出于某種原因考慮,刪去了其中一些元素,剩下下面這些。
~~~
HTTP/1.1 200 OK
Content-Type: application/json
Date: Fri, 05 Sep 2014 15:05:49 GMT
[{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}]
~~~
我們用curl命令向服務器發起了GET請求,服務器返回了上面的結果。
### 11.2.1 HTTP響應
一個HTTP響應由三部分組成
* 狀態行(狀態碼)
* 消息報頭(響應報頭)
* 響應正文(消息體)
#### 11.2.1.1 HTTP響應 狀態碼
在上面的結果中,狀態行是
~~~
HTTP/1.1 200 OK
~~~
返回的狀態碼是200,OK是狀態碼的原因短語。
如果是一個跳轉的頁面,它就可能是下面的結果:
~~~
HTTP/1.0 301 MOVED PERMANENTLY
Date: Mon, 08 Sep 2014 12:04:01 GMT
Content-Type: text/html; charset=utf-8
~~~
HTTP Status有五種狀態,而這五種狀態又有所細分,提一下這五種狀態,詳細可參見[http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81](http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)
* 1xx消息
* 2xx成功
* 3xx重定向
* 4xx客戶端錯誤
* 5xx服務器錯誤
如
* 200 ok - 成功返回狀態,對應,GET,PUT,PATCH,DELETE.
* 201 created - 成功創建。
* 304 not modified - HTTP緩存有效。
* 400 bad request - 請求格式錯誤。
* 401 unauthorized - 未授權。
* 403 forbidden - 鑒權成功,但是該用戶沒有權限。
* 404 not found - 請求的資源不存在
* 405 method not allowed - 該http方法不被允許。
* 410 gone - 這個url對應的資源現在不可用。
* 415 unsupported media type - 請求類型錯誤。
* 422 unprocessable entity - 校驗錯誤時用。
* 429 too many request - 請求過多。
#### 11.2.1.2 HTTP響應 響應報頭
在這次響應中,返回了兩個報頭,即
~~~
Content-Type: application/json
Date: Fri, 05 Sep 2014 15:05:49 GMT
~~~
Content-Type和Date,在這里的Context-Type是application/json,而通常情況下我們打開一個網站時,他的Content-Type應該是text/html。
~~~
Content-Type: text/html;
~~~
Content-Type是最重要的報頭。
#### 11.2.1.3 HTTP響應 響應正文
正文才是我們真正想要的內容,上面的都是寫給瀏覽器看的,一般的人不會去關注這些。
~~~
HTTP/1.1 200 OK
Server: phodal.com/0.17.5
Content-Type: application/json
[{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}]
~~~
通常這是以某種格式寫的,在這里是以JSON寫的,而對于一個網站的時候則是HTML,如:
~~~
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
</html>
~~~
那么這次GET請求返回的就是:
~~~
HTTP/1.0 200 OK
Date: Mon, 08 Sep 2014 12:04:01 GMT
Content-Type: text/html; charset=utf-8
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
[{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}]
</body>
</html>
~~~
雖然與第一次請求的結果在游覽器上看似乎是一樣的(ps:可能有微小的差異),然而其本質是不同的。
推薦及參考書目:
* 《Web性能權威指南》
* 《圖解HTTP》
* 《RESTful Web Services Cookbook》
* 《RESTful Web APIs》
[^URL]: URL 是 URI 的子集