Http工作原理


HTTP協議(HyperText Transfer Protocol,超文本傳輸協議)是用於從WWW服務器傳輸超文本到本地瀏覽器的傳送協議。它可以使瀏覽器更加高效,使網絡傳輸減少。它不僅保證計算機正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分,以及哪部分內容首先顯示(如文本先於圖形)等。

         在了解HTTP如何工作之前,我們先了解計算機之間的通信。

2. 計算機相互之間的通信

        互聯網的關鍵技術就是TCP/IP協議。兩台計算機之間的通信是通過TCP/IP協議在因特網上進行的。實際上這個是兩個協議:

        TCP : Transmission Control Protocol 傳輸控制協議和IP: Internet Protocol  網際協議。

        IP:計算機之間的通信

        IP協議是計算機用來相互識別的通信的一種機制,每台計算機都有一個IP.用來在internet上標識這台計算機。  IP 負責在因特網上發送和接收數據包。通過 IP,消息(或者其他數據)被分割為小的獨立的包,並通過因特網在計算機之間傳送。IP 負責將每個包路由至它的目的地。

        IP協議僅僅是允許計算機相互發消息,但它並不檢查消息是否以發送的次序到達而且沒有損壞(只檢查關鍵的頭數據)。為了提供消息檢驗功能,直接在IP協議上設計了傳輸控制協議TCP.

        

       TCP : 應用程序之間的通信

       TCP確保數據包以正確的次序到達,並且嘗試確認數據包的內容沒有改變。TCP在IP地址之上引端口(port),它允許計算機通過網絡提供各種服務。一些端口號為不同的服務保留,而且這些端口號是眾所周知。

       服務或者守護進程:在提供服務的機器上,有程序監聽特定端口上的通信流。例如大多數電子郵件通信流出現在端口25上,用於wwww的HTTP通信流出現在80端口上。

       當應用程序希望通過 TCP 與另一個應用程序通信時,它會發送一個通信請求。這個請求必須被送到一個確切的地址。在雙方“握手”之后,TCP 將在兩個應用程序之間建立一個全雙工 (full-duplex) 的通信,占用兩個計算機之間整個的通信線路。TCP 用於從應用程序到網絡的數據傳輸控制。TCP 負責在數據傳送之前將它們分割為 IP 包,然后在它們到達的時候將它們重組。

       TCP/IP 就是TCP 和 IP 兩個協議在一起協同工作,有上下層次的關系。

       TCP 負責應用軟件(比如你的瀏覽器)和網絡軟件之間的通信。IP 負責計算機之間的通信。TCP 負責將數據分割並裝入 IP 包,IP 負責將包發送至接收者,傳輸過程要經IP路由器負責根據通信量、網絡中的錯誤或者其他參數來進行正確地尋址,然后在它們到達的時候重新組合它們。

 

3. HTTP協議所在的協議層

      HTTP是基於TCP協議之上的。在TCP/IP協議參考模型的各層對應的協議如下圖,其中HTTP是應用層的協議。

      


 

4. HTTP請求響應模型   

       HTTP由請求和響應構成,是一個標准的客戶端服務器模型(B/S)。HTTP協議永遠都是客戶端發起請求,服務器回送響應。見下圖:

    

 

       HTTP是一個無狀態的協議。無狀態是指客戶機(Web瀏覽器)和服務器之間不需要建立持久的連接,這意味着當一個客戶端向服務器端發出請求,然后服務器返回響應(response),連接就被關閉了,在服務器端不保留連接的有關信息.HTTP遵循請求(Request)/應答(Response)模型。客戶機(瀏覽器)向服務器發送請求,服務器處理請求並返回適當的應答。所有HTTP連接都被構造成一套請求和應答。

 

5. HTTP工作過程      

     一次HTTP操作稱為一個事務,其工作整個過程如下:

     1 ) 、地址解析,

     如用客戶端瀏覽器請求這個頁面:http://localhost.com:8080/index.htm

     從中分解出協議名、主機名、端口、對象路徑等部分,對於我們的這個地址,解析得到的結果如下:
     協議名:http
     主機名:localhost.com
     端口:8080
     對象路徑:/index.htm

      在這一步,需要域名系統DNS解析域名localhost.com,得主機的IP地址。


    2)、封裝HTTP請求數據包

     把以上部分結合本機自己的信息,封裝成一個HTTP請求數據包


     3)封裝成TCP包,建立TCP連接(TCP的三次握手)

       在HTTP工作開始之前,客戶機(Web瀏覽器)首先要通過網絡與服務器建立連接,該連接是通過TCP來完成的,該協議與IP協議共同構建Internet,即著名的TCP/IP協議族,因此Internet又被稱作是TCP/IP網絡。HTTP是比TCP更高層次的應用層協議,根據規則,只有低層協議建立之后才能進行更高層協議的連接,因此,首先要建立TCP連接,一般TCP連接的端口號是80。這里是8080端口

     4)客戶機發送請求命令

       建立連接后,客戶機發送一個請求給服務器,請求方式的格式為:統一資源標識符(URI:Uniform Resource Identifier)、協議版本號,后邊是MIME信息包括請求修飾符、客戶機信息和可能的內容。

     5)服務器響應

     服務器接到請求后,給予相應的響應信息,其格式為一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,后邊是MIME信息包括服務器信息、實體信息和可能的內容。

        實體消息是服務器向瀏覽器發送頭信息后,它會發送一個空白行來表示頭信息的發送到此結束,接着,它就以Content-Type應答頭信息所描述的格式發送用戶所請求的實際數據

     6)服務器關閉TCP連接

     一般情況下,一旦Web服務器向瀏覽器發送了請求數據,它就要關閉TCP連接,然后如果瀏覽器或者服務器在其頭信息加入了這行代碼

    Connection:keep-alive

   TCP連接在發送后將仍然保持打開狀態,於是,瀏覽器可以繼續通過相同的連接發送請求。保持連接節省了為每個請求建立新連接所需的時間,還節約了網絡帶寬。

 

 

6. HTTP協議棧中各層數據流      

             首先我們看看客戶端請求的時候,數據在各層協議的數據組織如下圖:

         

            而服務器解析客戶機請求就是反向操作的過程,如下圖:

           
       

       客戶機發起一次請求的時候:

       客戶機會將請求封裝成http數據包-->封裝成Tcp數據包-->封裝成Ip數據包--->封裝成數據幀--->硬件將幀數據轉換成bit流(二進制數據)-->最后通過物理硬件(網卡芯片)發送到指定地點。

       服務器硬件首先收到bit流....... 然后轉換成ip數據包。於是通過ip協議解析Ip數據包,然后又發現里面是tcp數據包,就通過tcp協議解析Tcp數據包,接着發現是http數據包通過http協議再解析http數據包得到數據。

 

 

 

6. HTTPS實現原理    

 

             HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL。其所用的端口號是443。

 

         SSL:安全套接層,是netscape公司設計的主要用於web的安全傳輸協議。這種協議在WEB上獲得了廣泛的應用。通過證書認證來確保客戶端和網站服務器之間的通信數據是加密安全的。

 

 

      有兩種基本的加解密算法類型:

      1)對稱加密(symmetric encryption):密鑰只有一個,加密解密為同一個密碼,且加解密速度快,典型的對稱加密算法有DES、AES,RC5,3DES等;

       對稱加密主要問題是共享秘鑰,除你的計算機(客戶端)知道另外一台計算機(服務器)的私鑰秘鑰,否則無法對通信流進行加密解密。解決這個問題的方案非對稱秘鑰。

      2)非對稱加密:使用兩個秘鑰:公共秘鑰和私有秘鑰。私有秘鑰由一方密碼保存(一般是服務器保存),另一方任何人都可以獲得公共秘鑰。

      這種密鑰成對出現(且根據公鑰無法推知私鑰,根據私鑰也無法推知公鑰),加密解密使用不同密鑰(公鑰加密需要私鑰解密),相對對稱加密速度較慢,典型的非對稱加密算法有RSA、DSA等。

   下面看一下https的通信過程:

 

   

 

        過程大致如下:
        1) SSL客戶端通過TCP和服務器建立連接之后(443端口),並且在一般的tcp連接協商(握手)過程中請求證書。
              即客戶端發出一個消息給服務器,這個消息里面包含了自己可實現的算法列表和其它一些需要的消息,SSL的服務器端會回應一個數據包,這里面確定了這次通信所需要的算法,然后服務器向客戶端返回證書。(證書里面包含了服務器信息:域名。申請證書的公司,公共秘鑰)。                 
       2)Client在收到服務器返回的證書后,判斷簽發這個證書的公共簽發機構,並使用這個機構的公共秘鑰確認簽名是否有效,客戶端還會確保證書中列出的域名就是它正在連接的域名。
       3)  如果確認證書有效,那么生成對稱秘鑰並使用服務器的公共秘鑰進行加密。然后發送給服務器,服務器使用它的私鑰對它進行解密,這樣兩台計算機可以開始進行對稱加密進行通信。
 

https通信的優點:

1)客戶端產生的密鑰只有客戶端和服務器端能得到;

2)加密的數據只有客戶端和服務器端才能得到明文;

3)客戶端到服務端的通信是安全的。

 

 

 

 

7. HTTP各種長度限制   

 

 

 

1. URI長度限制

在Http1.1協議中並沒有提出針對URI的長度進行限制,RFC協議里面是這樣描述的,HTTP協議並不對URI的長度做任何的限制,服務器端必須能夠處理任何它們所提供服務多能接受的URI,並且能夠處理無限長度的URI,如果服務器不能處理過長的URI,那么應該返回414狀態碼。
 
 
雖然Http協議規定了,但是Web服務器和瀏覽器對URI都有自己的長度限制。
 
服務器的限制:我接觸的最多的服務器類型就是Nginx和Tomcat,對於url的長度限制,它們都是通過控制http請求頭的長度來進行限制的,nginx的配置參數為large_client_header_buffers,tomcat的請求配置參數為maxHttpHeaderSize,都是可以自己去進行設置。
 
瀏覽器的限制:每種瀏覽器也會對url的長度有所限制,下面是幾種常見瀏覽器的url長度限制:(單位:字符)
IE : 2803
Firefox:65536
Chrome:8182
Safari:80000
Opera:190000
 
對於get請求,在url的長度限制范圍之內,請求的參數個數沒有限制。
 

2. Post數據的長度限制

Post數據的長度限制與url長度限制類似,也是在Http協議中沒有規定長度限制,長度限制可以在服務器端配置最大http請求頭長度的方式來實現。
 

3. Cookie的長度限制

Cookie的長度限制分這么幾個方面來總結。
 
(1) 瀏覽器所允許的每個域下的最大cookie數目,沒有去自己測試,從網上找到的資料大概是這么個情況
IE :原先為20個,后來升級為50個
Firefox: 50個
Opera:30個
Chrome:180個
Safari:無限制
 
當Cookie數超過限制數時瀏覽器的行為:IE和Opera會采用LRU算法將老的不常使用的Cookie清除掉,Firefox的行為是隨機踢出某些Cookie的值。當然無論怎樣的策略,還是盡量不要讓Cookie數目超過瀏覽器所允許的范圍。
 
(2) 瀏覽器所允許的每個Cookie的最大長度
 
Firefox和Safari:4079字節
Opera:4096字節
IE:4095字節
 
(3) 服務器中Http請求頭長度的限制。Cookie會被附在每次http請求頭中傳遞給服務器,因此還會受到服務器請求頭長度的影響。
 

4. Html5 LocalStorage

Html5提供了本地存儲機制來供Web應用在客戶端存儲數據,盡管這個並不屬於Http協議的一部分,但是隨着Html5的流行,我們可能需要越來越多使用LocalStorage,甚至當它普及的時候跟它打交道就會同今天我們跟Cookie打交道一樣多。
 
對於LocalStorage的長度限制,同Cookie的限制類似,也是瀏覽器針對域來限制,只不過cookie限制的是個數,LocalStorage限制的是長度:
 
Firefox\Chrome\Opera都是允許每個域的最大長度為5MB

但是這次IE比較大方,允許的最大長度是10MB

 

客戶端通過發送 HTTP 請求向服務器請求對資源的訪問。 它向服務器傳遞了一個數據塊,也就是請求信息,HTTP 請求由三部分組成:請求行、  請求頭和請求正文。

 請求行:請求方法 URI 協議/版本

  請求頭(Request Header)

 

 請求正文

下面是一個HTTP請求的數據:

POST /index.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/
Content-Length:25
Content-Type:application/x-www-form-urlencoded
 
username=aa&password=1234
 

1、請求行:請求方法URI協議/版本

 請求的第一行是“方法 URL  協議/版本”,並以 回車換行作為結尾。請求行以空格分隔。格式如下:
POST /index.php HTTP/1.1
以上代碼中“GET”代表請求方法,“//ndex.php”表示URI,“HTTP/1.1代表協議和協議的版本。
        根據HTTP標准,HTTP請求可以使用多種請求方法。例如:HTTP1.1支持7種請求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet應用中,最常用的方法是GET和POST。
         URL完整地指定了要訪問的網絡資源,通常只要給出相對於服務器的根目錄的相對目錄即可,因此總是以“/”開頭,最后,協議版本聲明了通信過程中使用HTTP的版本。   

請求方法

在 HTTP 協議中,HTTP 請求可以使用多種請求方法,這些方法指明了要以何種方式來訪問 Request-URI 所標識的資源。HTTP1.1 支持的請求方法如下表所示:

HTTP1.1 中的請求方式:
方法 作用
GET 請求獲取由 Request-URI 所標識的資源
POST 請求服務器接收在請求中封裝的實體,並將其作為由 Request-Line 中的 Request-URI 所標識的資源的一部分
HEAD 請求獲取由 Request-URI 所標識的資源的響應消息報頭
PUT

請求服務器存儲一個資源,並用 Request-URI 作為其標識符

DELETE 請求服務器刪除由 Request-URI 所標識的資源
TRACE 請求服務器回送到的請求信息,主要用於測試或診斷
CONNECT 保留將來使用
OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求
 

重點介紹 GET、POST 和 HEAD 三個方法:

(1)GET

        GET 方法用於獲取由 Request-URI 所標識的資源的信息,常見的形式是:

        GET Request-URI HTTP/1.1
        GET方法是默認的HTTP請求方法,例如當我們通過在瀏覽器的地址欄中直接輸入網址的方式去訪問網頁的時候,瀏覽器采用的就是 GET 方法向服務器獲取資源。

        我們可以使用GET方法來提交表單數據,用GET方法提交的表單數據只經過了簡單的編碼,同時它將作為URL的一部分向服務器發送,因此,如果使用GET方法來提交表單數據就存在着安全隱患上。例如:
         Http://localhost/login.php?username=aa&password=1234

        從上面的URL請求中,很容易就可以辯認出表單提交的內容。(?之后的內容)另外由於GET方法提交的數據是作為URL請求的一部分所以提交的數據量不能太大。這是因為瀏覽器對url的長度有限制

       各種瀏覽器也會對url的長度有所限制,下面是幾種常見瀏覽器的url長度限制:(單位:字符)

IE : 2803
Firefox:65536
Chrome:8182
Safari:80000
Opera:190000 

(2)POST

          POST方法是GET方法的一個替代方法,它主要是向Web服務器提交表單數據,尤其是大批量的數據。 在請求頭信息結束之后的兩個回車換行之后(實際是空一行),就是表單提交的數據。如上面提到的post表單數據:

        username=aa&password=1234

        POST方法克服了GET方法的一些缺點。通過POST方法提交表單數據時,數據不是作為URL請求的一部分而是作為標准數據傳送給Web服務器,這就克服了GET方法中的信息無法保密和數據量太小的缺點。因此,出於安全的考慮以及對用戶隱私的尊重,通常表單提交時采用POST方法。

  從編程的角度來講,如果用戶通過GET方法提交數據,則數據存放在QUERY_STRING環境變量中,而POST方法提交的數據則可以從標准輸入流中獲取。

 

 GET與POST方法有以下區別:

      1、  在客戶端,Get方式在通過URL提交數據,數據在URL中可以看到;POST方式,數據放在HTTP包的body中。

      2、 GET方式提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST則沒有此限制。

      3、安全性問題。正如在(1)中提到,使用 Get 的時候,參數會顯示在地址欄上,而 Post 不會。所以,如果這些數據是中文數據而且是非敏感數據,那么使用 get;如果用戶輸入的數據不是中文字符而且包含敏感數據,那么還是使用 post為好。

      4.、服務器取值方式不一樣。GET方式取值,如php可以使用$_GET來取得變量的值,而POST方式通過$_POST來獲取變量的值。

 

(3)HEAD

     HEAD 方法與 GET 方法幾乎是相同的,它們的區別在於 HEAD 方法只是請求消息報頭,而不是完整的內容。對於 HEAD 請求的回應部分來說,它的 HTTP 頭部中包含的信息與通過 GET 請求所得到的信息是相同的。利用這個方法,不必傳輸整個資源內容,就可以得到 Request-URI 所標識的資源的信息。這個方法通常被用於測試超鏈接的有效性,是否可以訪問,以及最近是否更新。

    要注意的是,在 HTML 文檔中,書寫 get 和 post,大小寫都可以,但在 HTTP 協議中的 GET 和 POST 只能是大寫形式。

2. 請求頭

每個頭域由一個域名,冒號(:)和域值三部分組成。域名是大小寫無關的,域值前可以添加任何數量的空格符,頭域可以被擴展為多行,在每行開始處,使用至少一個空格或制表符。

HTTP最常見的請求頭如下:

Transport 頭域

Connection:

作用:表示是否需要持久連接。

如果服務器看到這里的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1默認進行持久連接),它就可以利用持久連接的優點,當頁面包含多個元素時(例如Applet,圖片),顯著地減少下載所需要的時間。要實現這一點,服務器需要在應答中發送一個Content-Length頭,最簡單的實現方法是:先把內容寫入 ByteArrayOutputStream,然后在正式寫出內容之前計算它的大小;

例如: Connection: keep-alive   當一個網頁打開完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的  網頁,會繼續使用這一條已經建立的連接

例如:  Connection: close  代表一個Request完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接會關閉,  當客戶端再次發送Request,需要重新建立TCP連接。

Host(發送請求時,該報頭域是必需的)

Host請求報頭域主要用於指定被請求資源的Internet主機和端口號,它通常從HTTP URL中提取出來的。

eg:http://;localhost/index.html
瀏覽器發送的請求消息中,就會包含Host請求報頭域,如下:
Host:localhost

此處使用缺省端口號80,若指定了端口號8080,則變成:Host:localhost:8080

Client 頭域

Accept:

作用:瀏覽器可以接受的媒體類型(MIME類型),

例如:  Accept: text/html  代表瀏覽器可以接受服務器回發的類型為 text/html  也就是我們常說的html文檔, 如果服務器無法返回text/html類型的數據,服務器應該返回一個406錯誤(non acceptable)。

通配符 * 代表任意類型。例如  Accept: */*  代表瀏覽器可以處理所有類型,(一般瀏覽器發給服務器都是發這個)

Accept-Encoding:

作用: 瀏覽器申明自己接收的編碼方法,通常指定壓縮方法,是否支持壓縮,支持什么壓縮方法(gzip,deflate),(注意:這不是只字符編碼);

例如: Accept-Encoding: gzip, deflate。Server能夠向支持gzip/deflate的瀏覽器返回經gzip或者deflate編碼的HTML頁面。 許多情形下這可以減少5到10倍的下載時間,也節省帶寬。

Accept-Language:

作用: 瀏覽器申明自己接收的語言。 

語言跟字符集的區別:中文是語言,中文有多種字符集,比如big5,gb2312,gbk等等;

例如: Accept-Language:zh-cn 。如果請求消息中沒有設置這個報頭域,服務器假定客戶端對各種語言都可以接受。

User-Agent:

作用:告訴HTTP服務器, 客戶端使用的操作系統和瀏覽器的名稱和版本.

我們上網登陸論壇的時候,往往會看到一些歡迎信息,其中列出了你的操作系統的名稱和版本,你所使用的瀏覽器的名稱和版本,這往往讓很多人感到很神奇,實際上, 服務器應用程序就是從User-Agent這個請求報頭域中獲取到這些信息User-Agent請求報頭域允許客戶端將它的操作系統、瀏覽器和其它屬性告訴服務器。

例如: User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; InfoPath.2; .NET4.0E)

Accept-Charset:

作用:瀏覽器申明自己接收的字符集,這就是本文前面介紹的各種字符集和字符編碼,如gb2312,utf-8(通常我們說Charset包括了相應的字符編碼方案);

例如:Accept-Charset:iso-8859-1,gb2312.如果在請求消息中沒有設置這個域,缺省是任何字符集都可以接受。

Authorization:授權信息,通常出現在對服務器發送的WWW-Authenticate頭的應答中;

Authorization請求報頭域主要用於證明客戶端有權查看某個資源。當瀏覽器訪問一個頁面時,如果收到服務器的響應代碼為401(未授權),可以發送一個包含Authorization請求報頭域的請求,要求服務器對其進行驗證。

Cookie/Login 頭域

Cookie:

作用: 最重要的header, 將cookie的值發送給HTTP 服務器

Entity頭域

Content-Length

作用:發送給HTTP服務器數據的長度。即請求消息正文的長度;

例如: Content-Length: 38

Content-Type:

作用:

例如:Content-Type: application/x-www-form-urlencoded

Miscellaneous 頭域

Referer:

作用: 提供了Request的上下文信息的服務器,告訴服務器我是從哪個鏈接過來的,比如從我主頁上鏈接到一個朋友那里, 他的服務器就能夠從HTTP Referer中統計出每天有多少用戶點擊我主頁上的鏈接訪問    他的網站。

例如: Referer:http://translate.google.cn/?hl=zh-cn&tab=wT

Cache 頭域

If-Modified-Since:

作用: 把瀏覽器端緩存頁面的最后修改時間發送到服務器去,服務器會把這個時間與服務器上實際文件的最后修改時間進行對比。如果時間一致,那么返回304,客戶端就直接使用本地緩存文件。如果時間不一致,就會返回200和新的文件內容。客戶端接到之后,會丟棄舊文件,把新文件緩存起來,並顯示在瀏覽器中。

例如:If-Modified-Since: Thu, 09 Feb 2012 09:07:57 GMT。

If-None-Match:

作用: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 當用戶再次請求該資源時,將在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服務器驗證資源的ETag沒有改變(該資源沒有更新),將返回一個304狀態告訴客戶端使用本地緩存文件。否則將返回200狀態和新的資源和Etag.  使用這樣的機制將提高網站的性能

例如: If-None-Match: "03f2b33c0bfcc1:0"

Pragma:

作用: 防止頁面被緩存, 在HTTP/1.1版本中,它和Cache-Control:no-cache作用一模一樣

Pargma只有一個用法, 例如: Pragma: no-cache

注意: 在HTTP/1.0版本中,只實現了Pragema:no-cache, 沒有實現Cache-Control

Cache-Control:

作用: 這個是非常重要的規則。 這個用來指定Response-Request遵循的緩存機制。各個指令含義如下

Cache-Control:Public   可以被任何緩存所緩存()

Cache-Control:Private     內容只緩存到私有緩存中

Cache-Control:no-cache  所有內容都不會被緩存

2. HTTP響應格式      

      在接收和解釋請求消息后,服務器會返回一個 HTTP 響應消息。與 HTTP 請求類似,HTTP 響應也是由三個部分組成,分別是:狀態行、消息報頭和響應正文。如:

 
        

HTTP/1.1 200 OK Date: Sun, 17 Mar 2013 08:12:54 GMT Server: Apache/2.2.8 (Win32) PHP/5.2.5 X-Powered-By: PHP/5.2.5 Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 4393 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=utf-8

<html> <head> <title>HTTP響應示例<title> </head> <body> Hello HTTP! </body> </html>

 

1、狀態行

       狀態行由協議版本、數字形式的狀態代碼,及相應的狀態描述組成,各元素之間以空格分隔,結尾時回車換行符,格式如下:

HTTP-Version Status-Code Reason-Phrase CRLF

HTTP-Version 表示服務器 HTTP 協議的版本,Status-Code 表示服務器發回的響應代碼,Reason-Phrase 表示狀態代碼的文本描述,CRLF 表示回車換行。例如:

HTTP/1.1 200 OK (CRLF)

      狀態代碼與狀態描述

      狀態代碼由 3 位數字組成, 表示請求是否被理解或被滿足,狀態描述給出了關於狀態碼的簡短的文字描述。狀態碼的第一個數字定義了響應類別,后面兩位數字沒有具體分類。第一個數字有 5 種取值,如下所示。

  • 1xx:指示信息——表示請求已經接受,繼續處理
  • 2xx:成功——表示請求已經被成功接收、理解、接受。
  • 3xx:重定向——要完成請求必須進行更進一步的操作
  • 4xx:客戶端錯誤——客戶端請求有錯誤或請求無法實現
  • 5xx:服務器端錯誤——服務器未能實現合法的請求。

常見狀態代碼、狀態描述、說明:
200 OK      //客戶端請求成功

303:重定向,即從原url重定向到新的url。 例如php 的hear函數header("localtion:/index.php")

400 Bad Request  //客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized //請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用 
403 Forbidden  //服務器收到請求,但是拒絕提供服務,一般是服務器路徑沒有權限或者是其他權限相關問題
404 Not Found  //請求資源不存在,eg:輸入了錯誤的URL
500 Internal Server Error //服務器發生不可預期的錯誤:一般來說,這個問題都會在服務器端的源代碼出現錯誤時出現,比如出現死循環。

502 Bad Gateway//作為網關或者代理工作的服務器嘗試執行請求時,從上游服務器接收到無效的響應。比如LNMP ,php-fpm沒有啟動就會報502錯誤。

503 Server Unavailable  //服務器當前不能處理客戶端的請求,一段時間后可能恢復正常,比如java 容器部署war的時候,就出現503, 
                                           或者是nginx處理的文件沒有權限。

 

504 Gateway Time-out:作為網關或者代理工作的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應,比如nginx和php-fpm, php設置sleep(200),就會收到504 Gateway Time-out。注意:某些代理服務器在DNS查詢超時時會返回400或者500錯誤

 

2、響應正文

響應正文就是服務器返回的資源的內容,響應頭和正文之間也必須用空行分隔。如:

 

[html]  view plain  copy
 
  1. <html>  
  2. <head>  
  3. <title>HTTP響應示例<title>  
  4. </head>  
  5. <body>  
  6. Hello HTTP!  
  7. </body>  
  8. </html>  

3 、響應頭信息

HTTP最常見的響應頭如下所示:

Cache頭域

Date:

作用:生成消息的具體時間和日期,即當前的GMT時間。

例如: Date: Sun, 17 Mar 2013 08:12:54 GMT

Expires:

作用: 瀏覽器會在指定過期時間內使用本地緩存,指明應該在什么時候認為文檔已經過期,從而不再緩存它。

例如: Expires: Thu, 19 Nov 1981 08:52:00 GMT  

Vary

作用:

例如: Vary: Accept-Encoding

Cookie/Login 頭域

P3P

作用: 用於跨域設置Cookie, 這樣可以解決iframe跨域訪問cookie的問題

例如: P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR

Set-Cookie

作用: 非常重要的header, 用於把cookie 發送到客戶端瀏覽器, 每一個寫入cookie都會生成一個Set-Cookie.

例如: Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/

Entity實體頭域:

            實體內容的屬性,包括實體信息類型,長度,壓縮方法,最后一次修改時間,數據有效性等。

ETag:

作用:  和If-None-Match 配合使用。 (實例請看上節中If-None-Match的實例)

例如: ETag: "03f2b33c0bfcc1:0"

Last-Modified:

作用: 用於指示資源的最后修改日期和時間。(實例請看上節的If-Modified-Since的實例)

例如: Last-Modified: Wed, 21 Dec 2011 09:09:10 GMT

Content-Type:

作用:WEB服務器告訴瀏覽器自己響應的對象的類型和字符集,

例如:

        Content-Type: text/html; charset=utf-8

  Content-Type:text/html;charset=GB2312

  Content-Type: image/jpeg

Content-Length:

指明實體正文的長度,以字節方式存儲的十進制數字來表示。在數據下行的過程中,Content-Length的方式要預先在服務器中緩存所有數據,然后所有數據再一股腦兒地發給客戶端。

  例如: Content-Length: 19847

Content-Encoding:

作用:文檔的編碼(Encode)方法。一般是壓縮方式。

WEB服務器表明自己使用了什么壓縮方法(gzip,deflate)壓縮響應中的對象。利用gzip壓縮文檔能夠顯著地減少HTML文檔的下載時間。

例如:Content-Encoding:gzip

Content-Language:

作用: WEB服務器告訴瀏覽器自己響應的對象的語言者

例如: Content-Language:da

Miscellaneous 頭域

Server:

作用:指明HTTP服務器的軟件信息

例如:Apache/2.2.8 (Win32) PHP/5.2.5

X-Powered-By:

作用:表示網站是用什么技術開發的

例如: X-Powered-By: PHP/5.2.5

Transport頭域

Connection:

例如: Connection: keep-alive   當一個網頁打開完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經建立的連接

例如:  Connection: close  代表一個Request完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接會關閉, 當客戶端再次發送Request,需要重新建立TCP連接。

Location頭域

Location:

作用: 用於重定向一個新的位置, 包含新的URL地址

實例請看304狀態實例

HTTP協議是無狀態的和Connection: keep-alive的區別

  無狀態是指協議對於事務處理沒有記憶能力,服務器不知道客戶端是什么狀態。從另一方面講,打開一個服務器上的網頁和你之前打開這個服務器上的網頁之間沒有任何聯系。

  HTTP是一個無狀態的面向連接的協議,無狀態不代表HTTP不能保持TCP連接,更不能代表HTTP使用的是UDP協議(無連接)。

  從HTTP/1.1起,默認都開啟了Keep-Alive,保持連接特性,簡單地說,當一個網頁打開完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經建立的連接。

  Keep-Alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。

 

3. 瀏覽器緩存      

          

       瀏覽器緩存:包括頁面html緩存和圖片js,css等資源的緩存。如下圖,瀏覽器緩存是基於把頁面信息保存到用戶本地電腦硬盤里。

        

 

 

1、緩存的優點:

 

     1)服務器響應更快:因為請求從緩存服務器(離客戶端更近)而不是源服務器被相應,這個過程耗時更少,讓服務器看上去響應更快。

     2)減少網絡帶寬消耗:當副本被重用時會減低客戶端的帶寬消耗;客戶可以節省帶寬費用,控制帶寬的需求的增長並更易於管理。

1、緩存工作原理

       頁面緩存狀態是由http header決定的,一個瀏覽器請求信息,一個是服務器響應信息。主要包括Pragma: no-cache、Cache-Control、 Expires、 Last-Modified、If-Modified-Since。其中Pragma: no-cache由HTTP/1.0規定,Cache-Control由HTTP/1.1規定。

       工作原理圖:

 

從圖中我們可以看到原理主要分三步:

  1. 第一次請求:瀏覽器通過http的header報頭,附帶Expires,Cache-Control,Last-Modified/Etag向服務器請求,此時服務器記錄第一次請求的Last-Modified/Etag                  
  2. 再次請求:當瀏覽器再次請求的時候,請求頭附帶Expires,Cache-Control,If-Modified-Since/Etag向服務器請求
  3. 服務器根據第一次記錄的Last-Modified/Etag和再次請求的If-Modified-Since/Etag做對比,判斷是否需要更新,服務器通過這兩個頭判斷本地資源未發生變化,客 戶端不需要重新下載,返回304響應。常見流程如下圖所示:
 

 

與緩存相關的HTTP擴展消息頭

 

    Expires:設置頁面過期時間,格林威治時間GMT

    Cache-Control:更細致的控制緩存的內容

    Last-Modified:請求對象最后一次的修改時間 用來判斷緩存是否過期 通常由文件的時間信息產生 

    ETag:響應中資源的校驗值,在服務器上某個時段是唯一標識的。ETag是一個可以 與Web資源關聯的記號(token),和Last-Modified功能才不多,也是一個標識符,一般和Last-Modified一起使用,加強服務器判斷的准確度。

    Date:服務器的時間

    If-Modified-Since:客戶端存取的該資源最后一次修改的時間,用來和服務器端的Last-Modified做比較

    If-None-Match:客戶端存取的該資源的檢驗值,同ETag。

Cache-Control的主要參數 
      Cache-Control: private/public Public 響應會被緩存,並且在多用戶間共享。 Private 響應只能夠作為私有的緩存,不能再用戶間共享。
      Cache-Control: no-cache:不進行緩存 
      Cache-Control: max-age=x:緩存時間 以秒為單位 
      Cache-Control: must-revalidate:如果頁面是過期的 則去服務器進行獲取。

 

我們nginx測試:

server {
        listen       8081;
        server_name  10.163.1.175;
        if ($host != 'www.test1.com' ) {
            #rewrite ^/(.*)$ http://www.test1.com/$1 permanent;
        }
        index index.html index.htm index.php;
        root  /home/www/app/;


        access_log  /mnt/app/nginx/logs/test1.home.log  main;


        location ~ .*\.zip?$
        {
               access_log off;
        }
        location ~ .*\.txt?$ {
                access_log off;
        }


        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
                expires      30d;
        }


        location ~ .*\.(js|css|zip)?$
        {
                expires      12h;
        }




        if (!-e $request_filename) {
            rewrite ^/(.+)$ /index.php?url=$1 last;
            break;
        }


        location ~ .*\.(php|php5)?$
        {
                #fastcgi_pass  unix:/tmp/php-cgi.sock;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                include fastcgi.conf;
                add_header Content-Type text/html;
        }
}

然后我們代理兩個域名指向同一個端口:

server {
    listen  80;
    server_name   www.test1.com  test1.com;


    location / {
        proxy_pass         http://127.0.0.1:8081;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forward-For    $proxy_add_x_forwarded_for;
        proxy_set_header Access-Control-Allow-Origin *;
        proxy_next_upstream http_502 http_504 error timeout invalid_header;
    }
}
server {
    listen  80;
    server_name   www.test2.com  test2.com;


    location / {
        proxy_pass         http://127.0.0.1:8081;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forward-For    $proxy_add_x_forwarded_for;
        proxy_set_header Access-Control-Allow-Origin *;
        proxy_next_upstream http_502 http_504 error timeout invalid_header;
    }
}

 

我們訪問www.test2.com,直接指向www.test1.com,http是304響應。

 

當我們把8081端口的配置去掉

        if ($host != 'www.test1.com' ) {
            #rewrite ^/(.*)$ http://www.test1.com/$1 permanent;
        }
   重啟nginx,同一個訪問www.test2.com,發現還是直接跳轉到www.test1.com。

這是因為瀏覽器304緩存的問題。我們直接使用新瀏覽器訪問,就直接訪問就不會跳轉啦。

 

 

  

 

2、關於圖片,css,js,flash的緩存

這個主要通過服務器的配置來實現這個技術,如果使用apache服務器的話,可以使用mod_expires模塊來實現:

編譯mod_expires模塊:

Cd  /root/httpd-2.2.3/modules/metadata

/usr/local/apache/bin/apxs -i -a -c mod_expires.c //編譯

編輯httpd.conf配置:添加下面內容

<IfModule mod_expires.c>

ExpiresActive on

ExpiresDefault "access plus 1 month"

ExpiresByType text/html "access plus 1 months"

ExpiresByType text/css "access plus 1 months"

ExpiresByType image/gif "access plus 1 months"

ExpiresByType image/jpeg "access plus 1 months"

ExpiresByType image/jpg "access plus 1 months"

ExpiresByType image/png "access plus 1 months"

EXpiresByType application/x-shockwave-flash "access plus 1 months"

EXpiresByType application/x-javascript      "access plus 1 months"

#ExpiresByType video/x-flv "access plus 1 months"

</IfModule>

解釋:第一句--開啟服務

第二句--默認時間是一個月

在下面是關於各種類型的資源的緩存時間設置


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM