日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

HTTP Cache的實(shí)現(xiàn)介紹

系統(tǒng) 1823 0
我們都知道瀏覽器會(huì)緩存訪問過網(wǎng)站的網(wǎng)頁,瀏覽器通過URL地址訪問一個(gè)網(wǎng)頁,顯示網(wǎng)頁內(nèi)容的同時(shí)會(huì)在電腦上面緩存網(wǎng)頁內(nèi)容。如果網(wǎng)頁沒有更新的話,瀏覽器再次訪問這個(gè)URL地址的時(shí)候,就不會(huì)再次下載網(wǎng)頁,而是直接使用本地緩存的網(wǎng)頁。只有當(dāng)網(wǎng)站明確標(biāo)識(shí)資源已經(jīng)更新,瀏覽器才會(huì)再次下載網(wǎng)頁。

一、什么是HTTP Cache

對(duì)于瀏覽器的這種網(wǎng)頁緩存機(jī)制大家已經(jīng)耳熟能詳了,舉個(gè)例子來說,JavaEye的新聞?dòng)嗛喌刂罚篽ttp://www.iteye.com/rss/news , 當(dāng)瀏覽器或者訂閱程序訪問這個(gè)URL地址的時(shí)候,JavaEye的服務(wù)器在response的header里面會(huì)發(fā)送給瀏覽器如下狀態(tài)標(biāo)識(shí):

C代碼 收藏代碼
  1. Etag "427fe7b6442f2096dff4f92339305444"
  2. Last-ModifiedFri,04Sep200905:55:43GMT


這就是告訴瀏覽器,新聞?dòng)嗛嗊@個(gè)網(wǎng)絡(luò)資源的最后修改時(shí)間和Etag。于是瀏覽器把這兩個(gè)狀態(tài)信息連同網(wǎng)頁內(nèi)容在本地進(jìn)行緩存,當(dāng)瀏覽器再次訪問JavaEye新聞?dòng)嗛喌刂返臅r(shí)候,瀏覽器會(huì)發(fā)送如下兩個(gè)狀態(tài)標(biāo)識(shí)給JavaEye服務(wù)器:

C代碼 收藏代碼
  1. If-None-Match "427fe7b6442f2096dff4f92339305444"
  2. If-Modified-SinceFri,04Sep200905:55:43GMT


就是告訴服務(wù)器,我本地緩存的網(wǎng)頁最后修改時(shí)間和Etag是什么,請(qǐng)問你服務(wù)器的資源有沒有在我上次訪問之后有更新?。坑谑荍avaEye服務(wù)器會(huì)核對(duì)一下,如果該用戶上次訪問之后沒有更新過新聞,那么根本就不必生成這個(gè)RSS了,直接告訴瀏覽器:“沒什么新東西,你還是看自己緩存的網(wǎng)頁吧”,于是服務(wù)器就發(fā)送一個(gè)304 Not Modified的消息,其他什么都不用干了。

這就是HTTP層的Cache,使用這種基于資源的緩存機(jī)制,不但大大節(jié)省服務(wù)器程序資源,而且還減少了網(wǎng)頁下載次數(shù),節(jié)約了很多網(wǎng)絡(luò)帶寬。

二、HTTP Cache究竟有什么作用?

我們通常的動(dòng)態(tài)網(wǎng)站編程,服務(wù)器端程序根本就不去處理瀏覽器發(fā)送過來的If-None-Match和If-Modified-Since狀態(tài)標(biāo)識(shí),只要有請(qǐng)求就生成網(wǎng)頁發(fā)送給瀏覽器。對(duì)于一般情況來說,用戶不會(huì)總是沒完沒了刷新一個(gè)頁面,所以大家并不認(rèn)為這種基于資源的緩存有什么太大的作用,但實(shí)際情況并非如此:

1、像Google這種比較智能的網(wǎng)絡(luò)爬蟲可以有效識(shí)別資源的狀態(tài)信息,如果使用這種緩存機(jī)制,可以大大減少爬蟲的爬取次數(shù)。

比方說Google每天爬JavaEye網(wǎng)站大概15萬次左右,但實(shí)際上JavaEye每天有更新的內(nèi)容不會(huì)超過1萬個(gè)網(wǎng)頁。因?yàn)楹芏鄡?nèi)容更新比較快,因此Google就會(huì)反復(fù)不停的爬取,這樣本身就造成了很多資源的浪費(fèi)。如果我們使用HTTP Cache,那么只有當(dāng)網(wǎng)頁內(nèi)容發(fā)生改變的時(shí)候,才會(huì)真正進(jìn)行爬取,其他時(shí)候我們直接告訴Google的爬蟲304 Not Modified就可以了。這樣不但降低了服務(wù)器本身的負(fù)載和爬蟲造成的網(wǎng)絡(luò)帶寬消耗,實(shí)際上也大大提高了Google爬蟲的工作效率,豈不是皆大歡喜?

2、很多內(nèi)容更新不頻繁的網(wǎng)頁,盡管用戶不會(huì)頻繁的刷新,但是從一個(gè)比較長的時(shí)間段來看使用HTTP Cache,仍然可以起到很大的緩存作用。

比方說一些歷史討論帖子,已經(jīng)過去了幾個(gè)月了,這些帖子內(nèi)容很少更新。用戶可能通過搜索,收藏鏈接,文章關(guān)聯(lián)等方式時(shí)不時(shí)訪問到這個(gè)頁面。那么只要用戶訪問過一次以后,后續(xù)所有訪問服務(wù)器直接發(fā)送304 Not Modified就可以了,不用真正生成頁面。

3、對(duì)于歷史帖子使用HTTP Cache可以避免爬蟲反復(fù)的爬取。

比方說JavaEye的論壇帖子列表頁面,分頁到20頁后面的帖子已經(jīng)很少有人直接訪問了,但是從服務(wù)器日志去看,每天仍然有大量爬蟲反復(fù)爬取這些分頁到很后面的頁面。這些頁面由于用戶很少去點(diǎn)擊,所以基本上沒有被應(yīng)用程序的memcached緩存住,每次訪問都會(huì)造成很高的資源消耗,爬蟲隔一段時(shí)間就爬一次,對(duì)服務(wù)器是很大的負(fù)擔(dān)。如果使用了HTTP Cache,那么只要爬蟲爬過一次以后,以后無論爬蟲爬多少次,都可以直接返回304 Not Modified了,極大的節(jié)省了服務(wù)器的負(fù)載。

三、如何在應(yīng)用程序里面使用HTTP Cache

如果我們要在自己的程序里面實(shí)現(xiàn)HTTP Cache,是件非常簡單的事情,特別是對(duì)Rails來說只需要添加一點(diǎn)點(diǎn)代碼,以上面的JavaEye新聞?dòng)嗛唩碚f,只要添加一行代碼:

Ruby代碼 收藏代碼
  1. def news
  2. fresh_when( :last_modified =>News.last.created_at, :etag =>News.last)
  3. end


用最新新聞文章作為Etag,該文章最后修改時(shí)間作為資源的最后修改時(shí)間,這樣就OK了。如果瀏覽器發(fā)送過來的標(biāo)識(shí)和服務(wù)器標(biāo)識(shí)一致,說明內(nèi)容沒有更新,直接發(fā)送304 Not Modified;如果不一致,說明內(nèi)容更新,瀏覽器本地的緩存太古老了,那么就需要服務(wù)器真正生成頁面了。

以上只是一個(gè)最簡單的例子,如果我們需要根據(jù)狀態(tài)做一些更多的工作也是很容易的。比方說JavaEye博客的RSS訂閱地址: http://robbin.iteye.com/rss

Ruby代碼 收藏代碼
  1. @blogs = @blog_owner .last_blogs
  2. @hash = @blogs .collect{|b|{b.id=>b.post.modified_at.to_i+b.posts_count}}.hash
  3. if stale?( :last_modified =>( @blog_owner .last_blog.post.modified_at|| @blog_owner .last_blog.post.created_at), :etag => @hash )
  4. render :template => "rss/blog"
  5. end


這個(gè)實(shí)現(xiàn)稍微復(fù)雜一些。我們需要判斷博客訂閱所有的輸出文章是否有更新,所以我們用博客文章內(nèi)容最后修改時(shí)間和博客的評(píng)論數(shù)量做一個(gè)hash,然后用這個(gè)hash值作為資源的Etag,那么只要這些博客文章當(dāng)中任何文章內(nèi)容被修改,或者有新評(píng)論,都會(huì)改變Etag值,從而通知瀏覽器內(nèi)容有更新了。

除了RSS訂閱之外,JavaEye網(wǎng)站還有很多地方適合使用HTTP Cache,比方說JavaEye論壇的版面列表頁面,一些經(jīng)常喜歡泡論壇的用戶,可能時(shí)不時(shí)會(huì)上來刷新一下版面, 看看有沒有新的帖子,那么我們就不必每次用戶請(qǐng)求的時(shí)候都去執(zhí)行程序,生成頁面給他。我們判斷一下如果沒有新帖子的話,直接告訴他304 Not Modified就可以了,在沒有使用HTTP Cache之前的版面Action代碼:

Ruby代碼 收藏代碼
  1. def board
  2. @topics = @forum .topics.paginate...
  3. @announcements =(params[ :page ]||1).to_i==1?Topic.find :all , :conditions =>...
  4. render :action => 'show'
  5. end


添加HTTP Cache以后,代碼如下:

Ruby代碼 收藏代碼
  1. def board
  2. @topics = @forum .topics.paginate...
  3. if logged_in?||stale?( :last_modified => @topics [0].last_post.created_at, :etag => @topics .collect{|t|{t.id=>t.posts_count}}.hash)
  4. @announcements =(params[ :page ]||1).to_i==1?Topic.find :all , :conditions ...
  5. render :action => 'show'
  6. end
  7. end


對(duì)于登錄用戶,不使用HTTP Cache,這是因?yàn)榈卿浻脩粜枰獙?shí)時(shí)接收站內(nèi)短信通知和訂閱通知,因此我們只能對(duì)匿名用戶使用HTTP Cache,然后我們使用當(dāng)前所有帖子id和回帖數(shù)構(gòu)造hash作Etag,這樣只要當(dāng)前分頁列表頁面有任何帖子發(fā)生改變或者有了新回帖,就更新頁面,否則就不必重新生成頁面。

論壇帖子頁面實(shí)際上也可以使用HTTP Cache,只不過Etag的hash算法稍微復(fù)雜一些,需要保證帖子的任何改動(dòng)都要引起hash值的改變,示例代碼如下:

Ruby代碼 收藏代碼
  1. def show
  2. @topic =Topic.findparams[ :id ]
  3. user_session.update_....... if logged_in?
  4. Topic.increment_counter(...) if ......
  5. @posts = @topic .post_by_pageparams[ :page ]
  6. posts_hash= @posts .collect{|p|{p.id=>p.modified_at}}.hash
  7. topic_hash= @topic .forum_id+ @topic .sys_tag_id.to_i+ @topic .title.hash+ @topic .status_flag.hash
  8. ad_hash=...(廣告的hash算法,略)
  9. if logged_in?||stale?( :etag =>[posts_hash,topic_hash,ad_hash])
  10. render
  11. end
  12. end


要分別根據(jù)主題貼,該分頁的所有回帖和帖子頁面的廣告內(nèi)容進(jìn)行hash,計(jì)算出來一個(gè)唯一的Etag值,保證任何改動(dòng)都會(huì)生成新的Etag,這樣就搞定了,是不是很簡單!這種帖子的緩存非常有效,可以避免Rails去render頁面和下載頁面,極大的減輕了服務(wù)器負(fù)載和帶寬。

再舉一個(gè)需求比較特殊的例子:對(duì)于知識(shí)庫搜索相關(guān)文章的推薦頁面,比方說:http://www.iteye.com/wiki/topic/462476,也就是本文的相關(guān)文章推薦內(nèi)容,我們并不希望用戶和爬蟲每次訪問這個(gè)頁面都實(shí)際執(zhí)行一遍全文檢索,然后構(gòu)造頁面內(nèi)容,在一個(gè)相對(duì)不長的時(shí)間范圍內(nèi),這篇文章的相關(guān)推薦文章改變的概率不大,因此我們希望比方說5天之內(nèi),用戶重復(fù)訪問該頁面,就直接返回304 Not Modified,那么Rails沒有直接的設(shè)施給我們使用,需要我們稍微了解一些Rails的機(jī)制,自己編寫,代碼示例如下:

Ruby代碼 收藏代碼
  1. def topic
  2. @topic =Topic.find(params[ :id ])
  3. unless logged_in?
  4. if request.not_modified?(5.days.ago)
  5. head :not_modified
  6. else
  7. response.last_modified= Time .now
  8. end
  9. end
  10. end


每次用戶請(qǐng)求,我們判斷用戶是否5天之內(nèi)訪問過該頁面,如果訪問過,直接返回304 Not Modified,如果沒有訪問過,或者上次訪問已經(jīng)超過了5天,那么設(shè)置最近修改時(shí)間為當(dāng)前時(shí)間,然后生成頁面給用戶。是不是很簡單?

在給JavaEye網(wǎng)站所有的RSS訂閱輸出添加了HTTP Cache以后,通過一天的觀察發(fā)現(xiàn),超過一半的RSS訂閱請(qǐng)求已經(jīng)被緩存了,直接返回304 Not Modified,所以效果非常明顯,由于JavaEye網(wǎng)站每天RSS訂閱的動(dòng)態(tài)請(qǐng)求就超過了10萬次,因此添加HTTP Cache可以減輕不少服務(wù)器的負(fù)擔(dān)和帶寬消耗。除此之外,新聞文章頁面,整個(gè)論壇頻道,知識(shí)庫相關(guān)推薦文章頁面都可以添加HTTP Cache,粗粗計(jì)算下來,JavaEye這些頁面統(tǒng)統(tǒng)使用HTTP Cache以后,網(wǎng)站整體性能至少可以提高10%。

HTTP Cache的實(shí)現(xiàn)介紹


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 涞水县| 浙江省| 西平县| 北碚区| 临西县| 嘉善县| 岢岚县| 利辛县| 天长市| 紫阳县| 昌图县| 兰西县| 甘谷县| 新乡县| 苍南县| 华坪县| 桂平市| 乌兰察布市| 册亨县| 讷河市| 商南县| 通化县| 鄂州市| 张家界市| 都昌县| 阿坝县| 兴义市| 石屏县| 介休市| 佳木斯市| 长宁区| 高碑店市| 光山县| 班戈县| 芦山县| 阳新县| 宁远县| 诸城市| 万载县| 调兵山市| 阜新|