# HTTP協議簡介
在Web應用中,服務器把網頁傳給瀏覽器,實際上就是把網頁的HTML代碼發送給瀏覽器,讓瀏覽器顯示出來。而瀏覽器和服務器之間的傳輸協議是HTTP,所以:
* HTML是一種用來定義網頁的文本,會HTML,就可以編寫網頁;
* HTTP是在網絡上傳輸HTML的協議,用于瀏覽器和服務器的通信。
在舉例子之前,我們需要安裝Google的[Chrome瀏覽器](http://www.google.com/intl/zh-CN/chrome/)。
為什么要使用Chrome瀏覽器而不是IE呢?因為IE實在是太慢了,并且,IE對于開發和調試Web應用程序完全是一點用也沒有。
我們需要在瀏覽器很方便地調試我們的Web應用,而Chrome提供了一套完整地調試工具,非常適合Web開發。
安裝好Chrome瀏覽器后,打開Chrome,在菜單中選擇“視圖”,“開發者”,“開發者工具”,就可以顯示開發者工具:

`Elements`顯示網頁的結構,`Network`顯示瀏覽器和服務器的通信。我們點`Network`,確保第一個小紅燈亮著,Chrome就會記錄所有瀏覽器和服務器之間的通信:

當我們在地址欄輸入`www.sina.com.cn`時,瀏覽器將顯示新浪的首頁。在這個過程中,瀏覽器都干了哪些事情呢?通過`Network`的記錄,我們就可以知道。在`Network`中,定位到第一條記錄,點擊,右側將顯示`Request Headers`,點擊右側的`view source`,我們就可以看到瀏覽器發給新浪服務器的請求:

最主要的頭兩行分析如下,第一行:
```
GET / HTTP/1.1
```
`GET`表示一個讀取請求,將從服務器獲得網頁數據,`/`表示URL的路徑,URL總是以`/`開頭,`/`就表示首頁,最后的`HTTP/1.1`指示采用的HTTP協議版本是1.1。目前HTTP協議的版本就是1.1,但是大部分服務器也支持1.0版本,主要區別在于1.1版本允許多個HTTP請求復用一個TCP連接,以加快傳輸速度。
從第二行開始,每一行都類似于`Xxx: abcdefg`:
```
Host: www.sina.com.cn
```
表示請求的域名是`www.sina.com.cn`。如果一臺服務器有多個網站,服務器就需要通過`Host`來區分瀏覽器請求的是哪個網站。
繼續往下找到`Response Headers`,點擊`view source`,顯示服務器返回的原始響應數據:

HTTP響應分為Header和Body兩部分(Body是可選項),我們在`Network`中看到的Header最重要的幾行如下:
```
200 OK
```
`200`表示一個成功的響應,后面的`OK`是說明。失敗的響應有`404 Not Found`:網頁不存在,`500 Internal Server Error`:服務器內部出錯,等等。
```
Content-Type: text/html
```
`Content-Type`指示響應的內容,這里是`text/html`表示HTML網頁。請注意,瀏覽器就是依靠`Content-Type`來判斷響應的內容是網頁還是圖片,是視頻還是音樂。瀏覽器并不靠URL來判斷響應的內容,所以,即使URL是`http://example.com/abc.jpg`,它也不一定就是圖片。
HTTP響應的Body就是HTML源碼,我們在菜單欄選擇“視圖”,“開發者”,“查看網頁源碼”就可以在瀏覽器中直接查看HTML源碼:

當瀏覽器讀取到新浪首頁的HTML源碼后,它會解析HTML,顯示頁面,然后,根據HTML里面的各種鏈接,再發送HTTP請求給新浪服務器,拿到相應的圖片、視頻、Flash、JavaScript腳本、CSS等各種資源,最終顯示出一個完整的頁面。所以我們在`Network`下面能看到很多額外的HTTP請求。
## HTTP請求
跟蹤了新浪的首頁,我們來總結一下HTTP請求的流程:
步驟1:瀏覽器首先向服務器發送HTTP請求,請求包括:
方法:GET還是POST,GET僅請求資源,POST會附帶用戶數據;
路徑:/full/url/path;
域名:由Host頭指定:Host: www.sina.com.cn
以及其他相關的Header;
如果是POST,那么請求還包括一個Body,包含用戶數據。
步驟2:服務器向瀏覽器返回HTTP響應,響應包括:
響應代碼:200表示成功,3xx表示重定向,4xx表示客戶端發送的請求有錯誤,5xx表示服務器端處理時發生了錯誤;
響應類型:由Content-Type指定;
以及其他相關的Header;
通常服務器的HTTP響應會攜帶內容,也就是有一個Body,包含響應的內容,網頁的HTML源碼就在Body中。
步驟3:如果瀏覽器還需要繼續向服務器請求其他資源,比如圖片,就再次發出HTTP請求,重復步驟1、2。
Web采用的HTTP協議采用了非常簡單的請求-響應模式,從而大大簡化了開發。當我們編寫一個頁面時,我們只需要在HTTP請求中把HTML發送出去,不需要考慮如何附帶圖片、視頻等,瀏覽器如果需要請求圖片和視頻,它會發送另一個HTTP請求,因此,一個HTTP請求只處理一個資源。
HTTP協議同時具備極強的擴展性,雖然瀏覽器請求的是`http://www.sina.com.cn/`的首頁,但是新浪在HTML中可以鏈入其他服務器的資源,比如`<img src="http://i1.sinaimg.cn/home/2013/1008/U8455P30DT20131008135420.png">`,從而將請求壓力分散到各個服務器上,并且,一個站點可以鏈接到其他站點,無數個站點互相鏈接起來,就形成了World Wide Web,簡稱WWW。
## HTTP格式
每個HTTP請求和響應都遵循相同的格式,一個HTTP包含Header和Body兩部分,其中Body是可選的。
HTTP協議是一種文本協議,所以,它的格式也非常簡單。HTTP GET請求的格式:
```
GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
```
每個Header一行一個,換行符是`\r\n`。
HTTP POST請求的格式:
```
POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...
```
當遇到連續兩個`\r\n`時,Header部分結束,后面的數據全部是Body。
HTTP響應的格式:
```
200 OK
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...
```
HTTP響應如果包含body,也是通過`\r\n\r\n`來分隔的。請再次注意,Body的數據類型由`Content-Type`頭來確定,如果是網頁,Body就是文本,如果是圖片,Body就是圖片的二進制數據。
當存在`Content-Encoding`時,Body數據是被壓縮的,最常見的壓縮方式是gzip,所以,看到`Content-Encoding: gzip`時,需要將Body數據先解壓縮,才能得到真正的數據。壓縮的目的在于減少Body的大小,加快網絡傳輸。
要詳細了解HTTP協議,推薦“[HTTP: The Definitive Guide](http://shop.oreilly.com/product/9781565925090.do)”一書,非常不錯,有中文譯本:
[HTTP權威指南](http://t.cn/R7FguRq)
- JavaScript教程
- JavaScript簡介
- 快速入門
- 基本語法
- 數據類型和變量
- 字符串
- 數組
- 對象
- 條件判斷
- 循環
- Map和Set
- iterable
- 函數
- 函數定義和調用
- 變量作用域
- 方法
- 高階函數
- map/reduce
- filter
- sort
- 閉包
- 箭頭函數
- generator
- 標準對象
- Date
- RegExp
- JSON
- 面向對象編程
- 創建對象
- 原型繼承
- 瀏覽器
- 瀏覽器對象
- 操作DOM
- 更新DOM
- 插入DOM
- 刪除DOM
- 操作表單
- 操作文件
- AJAX
- Promise
- Canvas
- jQuery
- 選擇器
- 層級選擇器
- 查找和過濾
- 操作DOM
- 修改DOM結構
- 事件
- 動畫
- 擴展
- underscore
- Collections
- Arrays
- Functions
- Objects
- Chaining
- Node.js
- 安裝Node.js和npm
- 第一個Node程序
- 模塊
- 基本模塊
- fs
- stream
- http
- buffer
- Web開發
- koa
- mysql
- swig
- 自動化工具
- 期末總結
- Python 2.7教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷和循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 使用__future__
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- 常用第三方模塊
- PIL
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 協程
- gevent
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫數據庫模塊
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 添加配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- 期末總結
- Python3教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- async/await
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結
- Git教程
- Git簡介
- Git的誕生
- 集中式vs分布式
- 安裝Git
- 創建版本庫
- 時光機穿梭
- 版本回退
- 工作區和暫存區
- 管理修改
- 撤銷修改
- 刪除文件
- 遠程倉庫
- 添加遠程庫
- 從遠程庫克隆
- 分支管理
- 創建與合并分支
- 解決沖突
- 分支管理策略
- Bug分支
- Feature分支
- 多人協作
- 標簽管理
- 創建標簽
- 操作標簽
- 使用GitHub
- 自定義Git
- 忽略特殊文件
- 配置別名
- 搭建Git服務器
- 期末總結