http協議就是通訊的雙方共同遵照的標準,就比如要合夥辦事的兩家公司簽署的合同。javascript
openstack中各組件是基於restful api通訊的,restful api能夠單純的理解爲一個url地址:http://www.egon.com/index.htmlhtml
於是無論研究openstack內的任何組件,都離不開http協議,要想成爲一名合格的架構師,這些必須搞明白java
用戶從打開瀏覽器輸入網址到看到頁面經歷了什麼?python
1.首先必須web服務器運行web
2.客戶端運行瀏覽器軟件api
3.用戶輸入http://www.sina.com.cn/瀏覽器
4.客戶端瀏覽器處理http://www.sina.com.cn/,發起查詢本地DNS操做,將www.sina.com.cn->202.103.0.33緩存
5.客戶端瀏覽器發送http請求http://202.103.0.33:80/index.html (注意:80是web服務器的默認端口,index.html是默認的請求的資源)服務器
6.服務端web服務收到該http的request請求頭,從請求頭中獲取客戶端的方法GET/POST.../index.html這個路徑,及客戶端請求的其餘相關信息restful
7.服務端web服務根據取得的信息,回覆respone響應頭
響應頭中包含:
響應代碼:200表示成功,3xx表示重定向,4xx表示客戶端發送的請求有錯誤,5xx表示服務器端處理時發生了錯誤;
響應類型:由Content-Type指定;
以及其餘相關的Header;
一般服務器的HTTP響應會攜帶內容,也就是有一個Body,包含響應的內容,網頁的HTML源碼就在Body中,壓縮後返回給客戶端。
8.客戶端瀏覽器收到服務端發來的數據,解壓後解析html內容,用戶就看到網頁內容了
9.html內可能嵌套其餘的連接,比方說圖片、視頻、javascript腳本,flash等,客戶端瀏覽器會繼續發起http請求來獲取它們。這樣來自圖片和視頻的壓力就被分散到各個服務器,一個站點由無數個站點相互鏈接起來,就造成了World Wide Web,簡稱WWW。
綜上,其實就是一次http請求-響應的流程
web服務器即socket服務端,瀏覽器即socket客戶端,這叫B/S架構,B與S之間通訊的標準是HTTP協議(目前版本1.1,比1.0好在能夠容許多個http請求複用一個TCP鏈接)
HTTP(hypertext transport protocol),即超文本傳輸協議。這個協議詳細規定了瀏覽器和萬維網服務器之間互相通訊的規則。
HTTP就是一個通訊規則,通訊規則規定了客戶端發送給服務器的內容格式,也規定了服務器發送給客戶端的內容格式。其實咱們要學習的就是這個兩個格式!客戶端發送給服務器的格式叫「請求協議」;服務器發送給客戶端的格式叫「響應協議」。
特色:
URL:統一資源定位符,就是一個網址:協議名://域名:端口/路徑,例如:http://www.oldboy.cn:80/index.html
請求協議的格式以下:
請求首行; // 請求方式 請求路徑 協議和版本,例如:GET /index.html HTTP/1.1 請求頭信息;// 請求頭名稱:請求頭內容,即爲key:value格式,例如:Host:localhost 空行; // 用來與請求體分隔開 請求體。 // GET沒有請求體,只有POST有請求體。
瀏覽器發送給服務器的內容就這個格式的,若是不是這個格式服務器將沒法解讀!在HTTP協議中,請求有不少請求方法,其中最爲經常使用的就是GET和POST。不一樣的請求方法之間的區別,後面會一點一點的介紹。
GET請求
HTTP默認的請求方法就是GET
* 沒有請求體
* 數據必須在1K以內!
* GET請求數據會暴露在瀏覽器的地址欄中
GET請求經常使用的操做:
1. 在瀏覽器的地址欄中直接給出URL,那麼就必定是GET請求
2. 點擊頁面上的超連接也必定是GET請求
3. 提交表單時,表單默認使用GET請求,但能夠設置爲POST
GET / HTTP/1.1 Host: www.sina.com.cn Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8 Cookie: SINAGLOBAL=223.71.229.3_1484011627.259786; Apache=223.71.229.3_1484011627.259788
Cookie:SINAGLOBAL=223.71.229.3_1484011627.259786; Apache=223.71.229.3_1484011627.259788
由於不是第一次訪問這個地址,因此會在請求中把上一次服務器響應中發送過來的Cookie在請求中一併發送去過;這個Cookie的名字爲SINAGLOBALPOST請求
(1). 數據不會出如今地址欄中
(2). 數據的大小沒有上限
(3). 有請求體
(4). 請求體中若是存在中文,會使用URL編碼!
<!DOCTYPE html> <html> <body> <form method="post"> 用戶名:<br> <input type="text" name="username"> <br> 密碼:<br> <input type="text" name="password"> <input type="submit" value="登陸"> </form> </body> </html>
咱們都知道Http協議中參數的傳輸是"key=value"這種簡直對形式的,若是要傳多個參數就須要用「&」符號對鍵值對進行分割。如"?name1=value1&name2=value2",這樣在服務端在收到這種字符串的時候,會用「&」分割出每個參數,而後再用「=」來分割出參數值。 針對「name1=value1&name2=value2」咱們來講一下客戶端到服務端的概念上解析過程: 上述字符串在計算機中用ASCII嗎表示爲: 6E616D6531 3D 76616C756531 26 6E616D6532 3D 76616C756532。 6E616D6531:name1 3D:= 76616C756531:value1 26:& 6E616D6532:name2 3D:= 76616C756532:value2 服務端在接收到該數據後就能夠遍歷該字節流,首先一個字節一個字節的吃,當吃到3D這字節後,服務端就知道前面吃得字節表示一個key,再想後吃,若是遇到26,說明從剛纔吃的3D到26子節之間的是上一個key的value,以此類推就能夠解析出客戶端傳過來的參數。 如今有這樣一個問題,若是個人蔘數值中就包含=或&這種特殊字符的時候該怎麼辦。 好比說「name1=value1」,其中value1的值是「va&lu=e1」字符串,那麼實際在傳輸過程當中就會變成這樣「name1=va&lu=e1」。咱們的本意是就只有一個鍵值對,可是服務端會解析成兩個鍵值對,這樣就產生了奇異。 如何解決上述問題帶來的歧義呢?解決的辦法就是對參數進行URL編碼 URL編碼只是簡單的在特殊字符的各個字節前加上%,例如,咱們對上述會產生奇異的字符進行URL編碼後結果:「name1=va%26lu%3D」,這樣服務端會把緊跟在「%」後的字節當成普通的字節,就是不會把它當成各個參數或鍵值對的分隔符。 爲何要進行URL編碼
POST請求是能夠有體的,而GET請求不能有請求體。
Referer請求頭是比較有用的一個請求頭,它能夠用來作統計工做,也能夠用來作防盜鏈。
統計工做:我公司網站在百度上作了廣告,但不知道在百度上作廣告對咱們網站的訪問量是否有影響,那麼能夠對每一個請求中的Referer進行分析,若是Referer爲百度的不少,那麼說明用戶都是經過百度找到咱們公司網站的。
防盜鏈:我公司網站上有一個下載連接,而其餘網站盜鏈了這個地址,例如在我網站上的index.html頁面中有一個連接,點擊便可下載JDK7.0,但有某我的的微博中盜鏈了這個資源,它也有一個連接指向咱們網站的JDK7.0,也就是說登陸它的微博,點擊連接就能夠從我網站上下載JDK7.0,這致使咱們網站的廣告沒有看,但下載的倒是我網站的資源。這時可使用Referer進行防盜鏈,在資源被下載以前,咱們對Referer進行判斷,若是請求來自本網站,那麼容許下載,若是非本網站,先跳轉到本網站看廣告,而後再容許下載。
3.1 響應內容
響應協議的格式以下:
響應首行; 響應頭信息; 空行; 響應體。
響應內容是由服務器發送給瀏覽器的內容,瀏覽器會根據響應內容來顯示。遇到<img src=''>會開一個新的線程加載,因此有時圖片多的話,內容會先顯示出來,而後圖片才一張張加載出來。
#_*_coding:utf-8_*_ #!/usr/bin/env python from wsgiref.simple_server import make_server # 定義application函數: def application(environ, start_response): print(environ) start_response('200 OK', [('Content-Type', 'text/html')]) f=open('test.html','rb') return [f.read()] # 建立一個服務器,IP地址爲空,端口是8000,處理函數是application: httpd = make_server('', 8000, application) print('Serving HTTP on port 8000...') # 開始監聽HTTP請求: httpd.serve_forever()
<!DOCTYPE html> <html> <body> <form> 用戶名:<br> <input type="text" name="username"> <br> 密碼:<br> <input type="text" name="password"> <input type="submit" value="登陸"> </form> </body> </html>
3.2 狀態碼
響應頭對瀏覽器來講很重要,它說明了響應的真正含義。例如200表示響應成功了,302表示重定向,這說明瀏覽器須要再發一個新的請求。
當用戶第一次請求index.html時,服務器會添加一個名爲Last-Modified響應頭,這個頭說明了 index.html的最後修改時間,瀏覽器會把index.html內容,以及最後響應時間緩存下來。當用戶第 二次請求index.html時,在請求中包含一個名爲If-Modified-Since請求頭,它的值就是第一次請 求時服務器經過Last-Modified響應頭髮送給瀏覽器的值,即index.html最後的修改時間, If-Modified-Since請求頭就是在告訴服務器,我這裏瀏覽器緩存的index.html最後修改時間是這個, 您看看如今的index.html最後修改時間是否是這個,若是仍是,那麼您就不用再響應這個index.html 內容了,我會把緩存的內容直接顯示出來。而服務器端會獲取If-Modified-Since值,與index.html 的當前最後修改時間比對,若是相同,服務器會發響應碼304,表示index.html與瀏覽器上次緩存的相 同,無需再次發送,瀏覽器能夠顯示本身的緩存頁面,若是比對不一樣,那麼說明index.html已經作了修 改,服務器會響應200。
3.3 其餘響應頭
告訴瀏覽器不要緩存的響應頭:
自動刷新響應頭,瀏覽器會在3秒以後請求http://www.baidu.com:
3.4 HTML中指定響應頭
在HTMl頁面中可使用<meta http-equiv="" content="">來指定響應頭,例如在index.html頁面中給出<meta http-equiv="Refresh" content="3;url=http://www.baidu.com">,表示瀏覽器只會顯示index.html頁面3秒,而後自動跳轉到http://www.baidu.com.
咱們能夠打開瀏覽器在菜單中選擇」視圖「,「開發者」,"開發者工具",選擇Network來監控瀏覽器與web服務器之間作的事情。
web服務器收到的客戶端發來的請求頭
web服務器發給客戶端的響應頭(返回body就是html了)