PHP関連シリーズ-HTTPキャッシュの概念とブラウザにキャッシュの使用を強制する例

13557 ワード

静的htmlページの場合、ブラウザが初めてアクセスすると、そのページがキャッシュに格納されます.
再度このページにアクセスすると、リクエストヘッダが添付されます.
If-MOdified-Since:Mon,17 Sep 2012 08:52:31 GMTのようなデータ.
サーバに送信され、サーバが受信した後、この日付が変更されていないことを発見し、クライアントに応答するために304を送信する.クライアントはおとなしく自分のキャッシュを表示します.
CTRL+F 5を押したままにすると、強制的にリフレッシュされ、要求ヘッダにIf-MOdified-Sinceは含まれません.したがって、サーバは受信した後、直接200応答を送信する.
ASP.NETで使用したキャッシュについても同様の効果があります.たとえば、次のページコードです.
<%@ OutputCache Duration="600"VaryByParam="None"%>
default:<%Response.Write(DateTime.Now.ToString("yyyyMMdd")); %>
ここで、Location="ServerAndClient"が設定されている場合、2回目のアクセスは304応答です.このページにアクセスするときはhtmlにアクセスするのと同じで、2回目のアクセスには304の応答があります.もちろん、ページが更新されると、200の応答が得られます.それはリクエストヘッダにIf-MOdifid-Since:Tue,18 Sep 2012 12:32:14 GMTというデータがあるからです.(注:Chromeで試行すると304応答があります.ただしfirefoxで試行すると、リクエストヘッダにIf-Modified-Since情報がないため、304はなく、毎回200応答です.原因は不明です.)
ここでは、Location="Server"を設定すると、毎回200応答となります.このキャッシュはサーバメモリに格納されるため,毎回200であるが,ページ生成のオーバーヘッドを節約する.Location="Server"の場合、応答ヘッダはCache-Control:no-cacheになりますが、実際には応答ヘッダCache-Controlがno-cacheとマークされていてもローカルにキャッシュされますが、コンテンツが最新であるかどうかを初めて検証していない場合、cacheコンテンツをクライアントに送信することはありません.no-cacheのより良い名前は「最新であるかどうかを検証しないと出力しないcache」です(注:『HTTP The Definitive Guide』by David Gourley and Brian Tottyより)
ここで、Location="Client"を設定すると、毎回200応答となる.これが疑問な点である.クライアントはキャッシュされているが、要求ヘッダにもIf-MOdified-Sinceがあり、サーバデータも変更されていないが、200を返している.ここでは動的ページについては、特別な処理がなければ常に200状態を返していると推測する.
例えば、次のページは、phpページ、またはaspxページであると仮定します.このページの内容に動的コードがなくても.
例: 

  
  
  
  
  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3.     <title></title> 
  4. </head> 
  5. <body> 
  6.     <form id="form1"> 
  7.     <div> 
  8.       
  9.     </div> 
  10.     </form> 
  11. </body> 
  12. </html> 
  13.  

 リクエストのたびに常に200応答が得られ、キャッシュは使用されません.
次に、サーバ側が304状態を送信することによって、クライアントをだまして自分のキャッシュを呼び出し、ネットワーク圧力を緩和する目的を達成することを示す.
まず、いくつかのテストのルールを説明します.
response応答ヘッダlast-modifiedは、クライアントにキャッシュされた後、すなわちクライアントがリフレッシュされると、この値がクライアントのrequestリクエストヘッダの値となる.
例えば、Response.AddHeader(「last-modified」,new DateTime(2000,1,1,1)では、このページをリフレッシュまたは再発行する場合、Request.Headers["If-modified-Since"]の値は2001-01-01である.したがって、If-modified-Sinceは最後の更新時間をキャッシュするものと理解できる.
次の機能が実現されると仮定すると、クライアントがページを要求した後、10秒以内にクライアントが再び要求し、サーバ側は304ステータスコードを送信し、キャッシュの読み取りを要求する.(クライアントがCTRL+F 5でキャッシュの読み取りができない場合)
ASPXコードは以下のように実現される. 

  
  
  
  
  1. <%@ Page Title=" " Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
  2.     Inherits="WebApplication1._Default" %>  
  3. <%  
  4.     Response.Write("If - Modified - Since:" + Request.Headers["If-Modified-Since"] + "<br/>"); // If-Modified-Since  
  5.     Response.Write("Now:" + DateTime.Now.ToString() + "<br/>");//  
  6.     DateTime If_Modified_Since = new DateTime();  
  7.     if (Request.Headers["If-Modified-Since"] == null || Request.Headers["If-Modified-Since"] == "")  
  8.     {  
  9.         If_Modified_Since = new DateTime(1900, 1, 1);// If-Modified-Since , 19000101  
  10.     }  
  11.     else 
  12.     {  
  13.         If_Modified_Since = DateTime.Parse(Request.Headers["If-Modified-Since"]);  
  14.     }  
  15.     if (If_Modified_Since.AddSeconds(10) > DateTime.Now)// 10s  
  16.     {  
  17.         Response.StatusCode = 304;// 304 ,  
  18.         Response.End();  
  19.     }  
  20.     else//  
  21.     {  
  22.         //  
  23.         Response.AddHeader("last-modified", DateTime.Now.ToString());  
  24.         Response.Write("Content Changed;" + DateTime.Now.ToString()+"<br>");  
  25.     }  
  26. %>  

 PHPコードは以下の通りです. 

  
  
  
  
  1. <?php  
  2. date_default_timezone_set('PRC'); //    
  3.     $arr=getallheaders();  
  4.     $If_Modified_Since = new DateTime();  
  5.     if(isset($arr["If-Modified-Since"])==false)  
  6.     {  
  7.         $If_Modified_Since = new DateTime("1900-1-1");// If-Modified-Since , 19000101  
  8.     }  
  9.     else 
  10.     { //echo "##<br>";  
  11. //echo "If-Modified-Since:".$arr["If-Modified-Since"]."<br>";  
  12. //echo "##<br>";  
  13.         $If_Modified_Since = new DateTime($arr["If-Modified-Since"]);  
  14.     }  
  15. $now=new DateTime();  
  16. echo "##<br>";  
  17. echo $now->format('Y-m-d H:i:s')."---".$If_Modified_Since->format('Y-m-d H:i:s')."<br>";  
  18. echo "##<br>";  
  19. $diff=strtotime($now->format('Y-m-d H:i:s'))-strtotime($If_Modified_Since->format('Y-m-d H:i:s'));  
  20. echo "diff:"."$diff<br>";  
  21. if ($diff <10)// 10s  
  22.     {  
  23.        header('Etag:',true,304);// 304 ,  
  24.         exit();  
  25.     }  
  26.     else//  
  27.     {  
  28. $now=new DateTime();  
  29.         //  
  30. header ("last-modified:".$now->format('Y-m-d H:i:s'));   
  31.         print("Content Changed:" .$now->format('Y-m-d H:i:s')."<br>");  
  32.     }  
  33. ?>  
  34.  

 PHPページの例:
初回アクセス時に得られる応答ヘッダは200であり、要求ヘッダにはIf_Modified_Sinceは存在しない
10 s以内の再アクセス:
送信されたIf_Modified_Sinceヘッダの値は、2012-09-18 16:16:30です.サーバから現在の時間が10 s以内であるため、サーバは304を送信し、ブラウザにキャッシュを呼び出すように強制します.