淺析http協議、cookies和session機制、瀏覽器緩存

http協議中headerscookiessession、緩存等相關知識,發現些新知識點。  php

這篇文章注重結合PHP去理解這些內容,也就是比較注重實踐部分。 css

1、http headers           html

NO1對於web應用,用戶羣在客戶端 (各類瀏覽器)點擊任何一個鏈接向服務器發送http請求,這過程確定須要3次握手,創建鏈接,服務器響應返回數據。 nginx

每次請求都有頭部和實體部分,先看下面筆者監聽QQ空間的headersQQ空間的緣由是它頭部內容比較全
程序員

?web

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
     Request Headers: 
       
     GET http://user.qzone.qq.com/445235728 HTTP/1.1 
       
     Host: user.qzone.qq.com 
       
     Connection: keep-alive 
       
     Cache-Control: max-age=0 
       
     User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 
       
     Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
       
     Referer: http://qzone.qq.com/ 
       
     Accept-Encoding:gzip,deflate,sdch 
       
     Accept-Language: zh-CN,zh;q=0.8 
       
     Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3 
       
     Cookie:o_cookie=445235728;(省略不少……) 
       
     If-Modified-Since: Wed, 13 Jun 2012 01:32:19 GMT 
       
     ----------------- 
       
     Response Headers: 
       
     HTTP/1.1 200 OK 
       
     Connection:close 
       
     Server: QZHTTP-2.34.0 
       
     Date: Wed, 13 Jun 2012 02:59:31 GMT 
       
     Content-Encoding: gzip 
       
     Set-Cookie:login_time=61F0EEA02D704B1DBCF25166A74941B24F4BE24B205C466F;PATH=/; DOMAIN=qzone.qq.com 
       
     Set-Cookie:Loading=Yes;expires=Wed,13-Jun-201216:00:00GMT;PATH=/;DOMAIN=qzone.qq.com X-UA-Compatible: IE=Edge Last-Modified: Wed, 13 Jun 2012 02:59:31 GMT 
       
     Cache-Control: max-age=0, no-transform 
       
     Content-Type: text/html;charset=utf-8 
       
     Transfer-Encoding: chunked

客戶端向服務端發請求 headers 和服務端響應客戶端 headers 圖:  數據庫

 

經過圖片能夠看出: apache

一、客戶端請求headers包含了請求行和一些頭域。 瀏覽器

請求行:請求的方法 統一資源標識器(URL)協議版本 ------這三者用空格分開,最後換行回車(\r\n) 例如:GET http://user.qzone.qq.com/445235728 HTTP/1.1 緩存

各類頭域:這些頭域都是有關鍵字和鍵值成對組合,最後換行回車(\r\n)結束,這些頭域告訴服務器應該怎麼去響應以及自己一些信息。

二、服務器響應 

狀態行:協議版本 響應狀態 狀態描述 ------這三者用空格分開,最後換行回車(\r\n) 例如:HTTP/1.1 200 OK

各類頭域:這些頭域也是有關鍵字和鍵值成對組合,最後換行回車(\r\n)結束,這些頭域告訴客戶端應該怎麼去響應以及自己一些信息。

NO2

這裏就不一一說每一個頭域的概念和做用,想了解的請看:http://www.phpben.com/?post=34 如今介紹幾個認爲重要、在一些網站上的測試數據、以及請求返回各頭域php代碼實現

測試時間:2012.6.14前

測試對象:csdn cnbeta cnblos、騰訊(QQ空間、朋友網、新聞網)、新浪(微博、主頁)、人人網、百度、淘寶、優酷、土豆這些網站

(1)     Connection頭域:這個頭域只有http/1.1纔有,默認是keep-alive值表示長鏈接,這樣的話就不用每請求一個資源好比圖片,css文件,js文件都要和服務器進行3此握手鍊接,這個在必定程度上彌補了http沒狀態的一個缺陷,減小鏈接服務器的時間。

查看測試網站Connection頭域發現騰訊QQ空間、騰訊新聞網、新浪主頁和微博,優酷和土豆Connectionclose;除了這些其餘的都是Connectionkeep-alive

爲何?

1connection: keep-alive 能正常使用的一個前提條件是還要提供content-length的頭域告訴客戶端正文的長度。那計算正文長度是個問題,對於多內容,集羣服務器來講不是件易事。騰訊和新浪,優酷的這些都很難計算,對與工程師來講之間關閉了(默認是打開的)。

2、老服務器端不支持,對於騰訊,新浪這些老油條,服務器集羣很龐大,不免有些老舊的不支持長鏈接的,爲了一些兼容性問題,直接關閉了

Ps:這兩點緣由未求證過!^-^

php headers(「Connection:keep-alive」);

(2)     Content-Encoding頭域

Content-Encoding文檔的編碼(Encode)方法.

上述網站出了cnbeta不用gzip壓縮,優酷用deflate,其他都是。這也透漏一個重要信息,那就phper要掌握壓縮gzip傳輸技術。

Php能夠經過mod_gzip模塊來實現。代碼:ob_start("ob_gzhandler");

(3)     Server頭域暴漏服務器重要的安全信息。

CsdnServer:nginx/0.7.68  ------------版本都暴露

騰訊QQ空間:Server:QZHTTP-2.34.0--------某位tx朋友透漏這是內部本身開發的服務器,這個可夠安全

新浪微博:Server:apache -------------這個沒暴漏版本

鳳凰網:Server: nginx/0.8.53

人人網:Server:nginx/1.2.0

淘寶網:Tengine ---------這是淘寶內部技術團隊開發的web服務器,基於Nginx

cnblogs博客園:Server:Microsoft-IIS/7.5

騰訊朋友網:Tencent/PWS ---------騰訊內部開發

騰訊新聞網:Server:squid/3.1.18

優酷網:Server: fswww1-----------是否是內部就不清楚,至少筆者不知道什麼來的^_^

土豆網:Tengine/1.2.3

百度:server: BWS/1.0 ---------應該也是百度內部本身開發的服務器

很明顯Server頭域是返回服務器的信息,但也能夠說暴漏信息,面對這個問題,大公司就本身開發基於本身功能的內部服務器。

(4)     X-Powered-By頭域可供修改,基於安全則能夠修改

X-Powered-By頭域反應什麼語言什麼版本執行後臺程序。這個能夠同個header函數修改

header("X-Powered-By:acb");

(5)     Cache-controlexpireslast-modified等重要頭域

Cache-control:指定請求和響應遵循的緩存機制。在請求消息或響應消息中設置Cache-Control並不會修改另外一個消息處理過程當中的緩存處理過程。請求時的緩存指令包括no-cacheno-storemax-agemax-stalemin-freshonly-if-cached,響應消息中的指令包括publicprivateno-cacheno-storeno-transformmust-revalidateproxy-revalidatemax-age

Php代碼實現:header("cache-control: abc");abc是上述指令值一個或多個,多個用’,’分開

Expires:告訴瀏覽器指明應該在何時認爲文檔已通過期,從而再也不緩存它。代碼實現:header("Expires:". date('D, d M Y H:i:s \G\M\T', time()+10));--------這個是把時間截轉化成格林時區字符串給expires頭域,這個顯示時間會比中國北京時間少8個小時,東8區的實現:header("Expires:". date('r', time()+10))

last-modified:這個是服務器返回給瀏覽器,瀏覽器下次請求則把該值賦給if-modified-since頭域傳給服務器,服務器就能夠根據此值判斷是否有改變,有則繼續運行下去,否者返回304 not modifiedPhp設置expires頭域同樣。

代碼:

?

1
2
3
4
5
6
7
8
9
10
11
<?php
     if (isset( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) && (time()- strtotime ( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) < 10)) { 
       
       header( "HTTP/1.1 304 Not Modified" ); 
       
          exit
       
       
       
     header( "Last-Modified: " . date ( 'D, d M Y H:i:s \G\M\T' , time()) );或者header( "Last-Modified: " . date ( 'r' , time()) ); 
?>

前者是格林時間格式,後者是中國時間。須要注意的就是 php.ini 的時區 prc 則用後則,否者前者。筆者曾經試過在時區是 prc 的狀況下用了前者,致使 time()-strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) <0 永遠成立,由於是負值。

注意:當請求頁面有session_start()的時候,則不論是否有expirescache-controllast-modified設置,則返回給客戶端Cache-Control頭域爲Cache-Control:no-store, no-cache, must-revalidate Expires頭域 Expires:Thu, 19 Nov 1981 08:52:00 GMT。這個問題煩了筆者2天,都覺得php.ini 或是apache的問題。最後居然是session_start()的問題。

2、 瀏覽器緩存動態

前面介紹了http headers幾個告訴瀏覽器如何處理緩存。但不一樣瀏覽器處理各類頭域的方式不一樣,如下就是筆者。

Ps:各個瀏覽器監聽http headers的方法能夠查看:http://www.phpben.com/?post=76

(1)   header(「cache-control: no-store」)


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

同上

同上

同上

同上

 

(2)   header(「cache-control: no-cache」)


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

同上

From cache

From cache

同上

 

(3)   header(「cache-control:bublic」)


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

from cache

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

From cache

From cache

From cache

同上

(4)   header("cache-control:private"); header("cache-control: must-revalidate ")


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

除第一次外都是from cache

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

From cache

From cache

From cache

同上

(5)   header("cache-control:max-age=num");num是秒數


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

秒數<num from cache

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

From cache

From cache

From cache

同上

(6)   header("Expires:". date('D, d M Y H:i:s \G\M\T', time()+num)); num是秒數


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

地址欄回車

秒數<num from cache

重發請求,返回200狀態

重發請求,返回200狀態

重發請求,返回200狀態

點擊後退鍵

From cache

From cache

From cache

同上

(7)   if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (time()-strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < num)) {

  header("HTTP/1.1 304 Not Modified");

     exit;

   } header("Last-Modified: " . date('D, d M Y H:i:s \G\M\T', time()) );


IE9

Google17.0

Firefox11

Maxthon3

點擊刷新鍵

秒數<num 304 not modified

秒數<num 304 not modified

秒數<num 304 not modified

重發請求,返回200狀態

地址欄回車

from cache

秒數<num 304 not modified

秒數<num 304 not modified

重發請求,返回200狀態

點擊後退鍵

From cache

From cache

From cache

同上

 

結論:

一、   刷新對於任何瀏覽器且不論是什麼cache-control,都會從新請求,通常返回是200,除非Last-Modified設置

二、   後退鍵除非no-cache; no-store外都是使用緩存

三、   Cache-control:no-store 在瀏覽器中任何操做都從新提交請求,包括後退

四、   遨遊3的緩存不好

五、   IE9 的緩存很強,因此用ie9調試的時候儘量點刷新而不是在地址欄回車

鑑於這種狀況,對於不一樣的應用(有些要緩存,有些常常更新)對於不一樣的國家各類瀏覽器份額,而哪一種緩存方式。中國IE比較多,加上360瀏覽器的加入(用IE內核),那就要主要參照IE瀏覽器。

但筆者仍是比較喜歡header("Last-Modified: " . date('D, d M Y H:i:s \G\M\T', time()) );這種方式。結合起來connection:keep-alive能讓緩存技術更成熟。

注意

一、   也許你會問,用Cache-control:no-storeCache-control:no-store,但調試頁面仍是沒原來的緩存。而後清除瀏覽器緩存關掉重啓瀏覽器, 緩存還在。這是由於你的web應用用了文件緩存如ecshop常出現這種狀況,這種狀況就要進web應用後臺刪除文件緩存。

二、   調試的時候儘量不要在地址欄回車,特別是IEgoogle還好一點,可是要知道此次的測試只是各個瀏覽器中的一個版本,因此調試的時候儘量點刷新按鈕。

三、   但在cache-control:max-age=num expires 一塊兒使用的時候,前者級別比較高,瀏覽器會忽略expires的設置。(上面沒給出測試內容)

3、 Sessioncookies

Session cookies是程序員永遠討論的話題之一。

一、   簡單說一下cookiessession

(1)     Cookies是保存在客戶端的小段文本,隨客戶端點每個請求發送該url下的全部cookies到服務器端。好比在谷歌瀏覽器下,打開ww.abc.com下的兩個文件,a.php包含cookies1cookies2b.php包含了cookies3cookies4,那麼在a.phpb.php 點任意一個鏈接(固然是ww.abc.com服務器上的),瀏覽器就會把cookies1~44cookies發送給服務器。可是若是在IE9有打開一個包含cookies5c.php,哪門在google瀏覽器點擊鏈接是不會發送cookies5的。

(2)     Session則保存服務器段,經過惟一的值sessionID來區別每個用戶。SessionID隨每一個鏈接請求發送到服務器,服務器根據sessionID來識別客戶端,再經過session key獲取session值。SessionID傳回服務器的實現方式能夠經過cookiesurl回寫來實現。

注意

一、   同一個瀏覽器打開同一個文件,如a.php ,或同時有設置session的兩個文件a.phpb.php sessionID則只有一個。(時間上不能是打開a.php 關閉瀏覽器再打開b.php

二、   不一樣瀏覽器在同一時間打開贊成文件的sessionID也不同

三、   sessionID是服務器生成的不規則惟一字符串,如:

PHPSESSID=05dbfffd3453b7be02898fdca4fcd82b;------ PHPSESSID能夠經過php.inisession.name來改變,因此筆者在監聽一些大型網站的時候查不出PHPSESSID,這是一個安全因素。

(3)     cookiessessionphp中的主要相關參數

(1)     session.save_handler = 」files」

默認以文件方式存取session數據,若是想要使用自定義的處理器來存取session數據,好比數據庫,用」user」。

(2)     session.use_cookies = 1 前面說到sessionIDcookies來實現,這裏就是,1表示用cookies

(3)     session.use_trans_sid = 0 上面是用cookies來實現sessionID,這裏值如果1則使用url回寫方式,級別比session.use_cookies

(4)     session.use_only_cookies = 0 值爲1sessionID只能夠用cookies實現,級別比前兩個高

(5)     session.cache_expire =180  session 緩存過時的秒數

(6)     session.gc_maxlifetime = 1440

設定保存的session文件生存期,超過此參數設定秒數後,保存的數據將被視爲’垃圾’並由垃圾回收程序清理。判斷標準是最後訪問數據的時間(對於FAT文件系統是最後刷新數據的時間)。若是多個腳本共享同一個session.save_path目錄但session.gc_maxlifetime不一樣,將以全部session.gc_maxlifetime指令中的最小值爲準。

(4)     圖說cookie ssession

php代碼以下

?

1
2
3
4
5
6
7
8
9
10
11
session_start(); 
   
$_SESSION [ 'favcolor' ] = 'green'
   
$_SESSION [ 'animal' ]   = 'cat'
   
$_SESSION [ 'time' ]     = time(); 
   
setcookie( "cookie1" , "www.phpben.com" ,time()+3600*10); 
   
setcookie( "cookie2" , "www.phpben.com" ,time()+3600*10);

圖片:

結論:

1 第一次請求是沒用cookies的,而第二次有PHPSESSID和兩個cookies是由於服務器第一請求返回這個三個cookies

2、第二次請求比第一次多返回PHPSESSID這個cookies,在第二次則沒有了,直到session過時後從新設置。

二、   ;瀏覽器關掉cookiessession是否能夠正常運行?

前面說起sessionID的時候有兩種方式。

(1)     cookies 方式,在session.use_trans_sid=0 and session.use_cookies = 1的狀況下使用。這種方法是每次瀏覽器端點每一個請求,都把sessionID發送到服務器。

(2)     url回寫,session.use_only_cookies = 0 and session.use_trans_sid=1的狀況下,服務器會忽略session.use_trans_sid,在瀏覽器發hhtp請求後,服務器會在返回頁面內容中每一個鏈接後面加上PHPSESSID=05dbfffd3453b7be02898fdca4fcd82b (在php.ini沒改session.name,默認是PHPSESSID),這樣就算客戶端的瀏覽器禁止了cookies,同樣能實現session功能。

這裏來個測試:

1.php文件代碼:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php 
       
     echo 'Welcome to page #1<br/>'
       
     session_start(); 
       
     $_SESSION [ 'favcolor' ] = 'green'
       
     $_SESSION [ 'animal' ]   = 'cat'
       
     $_SESSION [ 'time' ]     = time(); 
       
        
       
     // Works if session cookie was accepted 
       
     echo '<br /><a href="2.php">page 1 (這個href中沒SID參數)</a><br/>'
       
        
       
     // Or maybe pass along the session id, if needed 
       
     echo '<br /><a href="2.php?' . SID . '">page 2 (這個href中有SID參數)</a><br/>'
       
     ?>

2.php 文件代碼:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php 
   
session_start(); 
   
    
   
echo 'Welcome to page #2<br />'
   
    
   
echo $_SESSION [ 'favcolor' ], '<br/>' ; // green 
   
echo $_SESSION [ 'animal' ], '<br/>' ;   // cat 
   
echo date ( 'Y m d H:i:s' , $_SESSION [ 'time' ]), '<br/>'
   
    
   
// You may want to use SID here, like we did in page1.php 
   
echo '<br /><a href="1.php">return page 1</a>'
   
?>

情景1:沒禁用瀏覽器的cookies(用cookies實現session),則在2.php能正常輸出

情景2:禁用用瀏覽器的cookies且在php.ini開啓session.use_trans_sid=1,經過1.php第一鏈接過去顯示不了session的值,但第二個鏈接則正常顯示。(說明url回寫正常運行)

相關文章
相關標籤/搜索