http的緩存機(jī)制在flask的實(shí)現(xiàn)

http協(xié)議有一系列的緩存機(jī)制(RFC2616)刻恭,相關(guān)的參數(shù)就在協(xié)議header中。緩存機(jī)制的合理使用可以大大減緩對(duì)服務(wù)器的壓力。

1 HTTP緩存頭的設(shè)置參數(shù)

HTTP緩存頭的參數(shù)包括:

  • Cache-Control(用于本地緩存)
  • Expires(用于本地緩存)
  • Last-Modified(協(xié)商緩存)
  • Etag(協(xié)商緩存)疗疟。

1.1 Cache-Control

指定請(qǐng)求和響應(yīng)遵循的緩存機(jī)制。在請(qǐng)求消息或響應(yīng)消息中設(shè)置Cache- Control并不會(huì)修改另一個(gè)消息處理過程中的緩 存處理過程瞳氓。

  • 請(qǐng)求時(shí)的緩存指令包括no-cache策彤、no-store、max-age匣摘、max-stale店诗、min-fresh、only-if- cached音榜;
  • 響應(yīng)消息中的指令包括public庞瘸、private、no-cache赠叼、no-store擦囊、no-transform、must- revalidate嘴办、proxy-revalidate瞬场、max-age。

1.2Expires

是一個(gè)絕對(duì)時(shí)間涧郊,作用與cache-control的max-age相類似贯被,表示資源信息失效的時(shí)間。

1.3 Last-Modified

被訪問的資源的最近一次更改時(shí)間(http1.0)

1.4 ETag

資源的一個(gè)唯一標(biāo)志(http1.1),通過這個(gè)標(biāo)識(shí)彤灶,可以實(shí)現(xiàn)客戶端與服務(wù)端的協(xié)商機(jī)制看幼。它的作用與Last-Modified是相類似的。

2 原理

是事實(shí)上枢希,上述四者的實(shí)現(xiàn)機(jī)制上桌吃,可以歸納為:

  • cache-control/Expires:資源有效時(shí)間定義機(jī)制
  • Last-Modified/ETag:資源更新傳輸協(xié)商機(jī)制

2.1 cache-control/Expires:資源有效時(shí)間定義機(jī)制

最好的請(qǐng)求是不必與服務(wù)器進(jìn)行通信的請(qǐng)求:通過響應(yīng)的本地副本,我們可以避免所有的網(wǎng)絡(luò)延遲以及數(shù)據(jù)傳輸?shù)臄?shù)據(jù)成本苞轿。為此,HTTP 規(guī)范允許服務(wù)器返回 一系列不同的 Cache-Control 指令逗物,控制瀏覽器或者其他中繼緩存如何緩存某個(gè)響應(yīng)以及緩存多長(zhǎng)時(shí)間搬卒。

cache-control控制緩存原理

一些參數(shù)的說明
  • no-cache和 no-store
    no-cache表示必須先與服務(wù)器確認(rèn)返回的響應(yīng)是否被更改,然后才能使用該響應(yīng)來滿足后續(xù)對(duì)同一個(gè)網(wǎng)址的請(qǐng)求翎卓。因此契邀,如果存在合適的驗(yàn)證令牌 (ETag),no-cache 會(huì)發(fā)起往返通信來驗(yàn)證緩存的響應(yīng)失暴,如果資源未被更改坯门,可以避免下載。
    相比之下逗扒,no-store更加簡(jiǎn)單古戴,直接禁止瀏覽器和所有中繼緩存存儲(chǔ)返回的任何版本的響應(yīng) - 例如:一個(gè)包含個(gè)人隱私數(shù)據(jù)或銀行數(shù)據(jù)的響應(yīng)。每次用戶請(qǐng)求該資源時(shí)矩肩,都會(huì)向服務(wù)器發(fā)送一個(gè)請(qǐng)求现恼,每次都會(huì)下載完整的響應(yīng)。
  • public和private
    如果響應(yīng)被標(biāo)記為public黍檩,即使有關(guān)聯(lián)的 HTTP 認(rèn)證叉袍,甚至響應(yīng)狀態(tài)碼無法正常緩存,響應(yīng)也可以被緩存刽酱。大多數(shù)情況下喳逛,public不是必須的,因?yàn)槊鞔_的緩存信息(例如max-age)已表示 響應(yīng)可以被緩存棵里。
    相比之下润文,瀏覽器可以緩存private響應(yīng),但是通常只為單個(gè)用戶緩存衍慎,因此转唉,不允許任何中繼緩存對(duì)其進(jìn)行緩存 - 例如,用戶瀏覽器可以緩存包含用戶私人信息的 HTML 網(wǎng)頁(yè)稳捆,但是 CDN 不能緩存赠法。
  • max-age
    該指令指定從當(dāng)前請(qǐng)求開始,允許獲取的響應(yīng)被重用的最長(zhǎng)時(shí)間(單位為秒) - 例如:max-age=60表示響應(yīng)可以再緩存和重用 60 秒。
  • 關(guān)于expires
    Cache-Control 頭在 HTTP/1.1 規(guī)范中定義砖织,取代了之前用來定義響應(yīng)緩存策略的頭(例如 Expires)款侵。當(dāng)前的所有瀏覽器都支持 Cache-Control,因此侧纯,使用它就夠了新锈。
  • cache-control在請(qǐng)求端和服務(wù)端的命令相互獨(dú)立
    cache-control不會(huì)因?yàn)檎?qǐng)求設(shè)置的值而修改響應(yīng)設(shè)置,反之亦然眶熬。這里考慮到一種場(chǎng)景妹笆,響應(yīng)頭中設(shè)置了一定的緩存時(shí)間,然而請(qǐng)求端仍然需要獲取最新結(jié)果娜氏,則將請(qǐng)求頭的緩存設(shè)置中加上“max-age=0”拳缠,則強(qiáng)制服務(wù)端響應(yīng)這個(gè)請(qǐng)求。

2.2 Last-Modified/ETag:資源更新傳輸協(xié)商機(jī)制

Last-Modified

在瀏覽器第一次請(qǐng)求某一個(gè)URL時(shí)贸弥,服務(wù)器端的返回狀態(tài)會(huì)是200窟坐,內(nèi)容是你請(qǐng)求的資源,同時(shí)有一個(gè)Last-Modified的屬性標(biāo)記此文件在服務(wù)期端最后被修改的時(shí)間绵疲,格式類似這樣:

Last-Modified: Fri, 12 May 2006 18:53:33 GMT 

客戶端第二次請(qǐng)求此URL時(shí)哲鸳,根據(jù) HTTP 協(xié)議的規(guī)定,瀏覽器會(huì)向服務(wù)器傳送 If-Modified-Since 報(bào)頭盔憨,詢問該時(shí)間之后文件是否有被修改過:

If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT

如果服務(wù)器端的資源沒有變化徙菠,則自動(dòng)返回 HTTP 304 (Not Changed.)狀態(tài)碼,內(nèi)容為空般渡,這樣就節(jié)省了傳輸數(shù)據(jù)量懒豹。當(dāng)服務(wù)器端代碼發(fā)生改變或者重啟服務(wù)器時(shí),則重新發(fā)出資源驯用,返回和第一次請(qǐng)求時(shí)類似脸秽。從而保證不向客戶端重復(fù)發(fā)出資源,也保證當(dāng)服務(wù)器有變化時(shí)蝴乔,客戶端能夠得到最新的資源记餐。

ETag

HTTP 協(xié)議規(guī)格說明定義ETag為“被請(qǐng)求變量的實(shí)體值” 。另一種說法是薇正,ETag是一個(gè)可以與Web資源關(guān)聯(lián)的記號(hào)(token)片酝。典型的Web資源可以一個(gè)Web頁(yè),但也可能是JSON或XML文檔挖腰。服務(wù)器單獨(dú)負(fù)責(zé)判斷記號(hào)是什么及其含義雕沿,并在HTTP響應(yīng)頭中將其傳送到客戶端,以下是服務(wù)器端返回的格式:

ETag: "50b1c1d4f775c61:df3" 

客戶端的查詢更新格式是這樣的:

If-None-Match: W/"50b1c1d4f775c61:df3" 

如果ETag沒改變猴仑,則返回狀態(tài)304然后不返回审轮,這也和Last-Modified一樣。

基于ETag驗(yàn)證的緩存原理

2.3 一種緩存分級(jí)策略實(shí)例

  • max-age=86400
    瀏覽器和任何中繼緩存均可以將響應(yīng)(如果是public的)緩存長(zhǎng)達(dá)一天(60 秒 x 60 分 x 24 小時(shí))
  • private, max-age=600
    客戶端瀏覽器只能將響應(yīng)緩存最長(zhǎng) 10 分鐘(60 秒 x 10 分)
  • no-cache
    通過ETag協(xié)商
  • no-store
    不允許緩存響應(yīng),每個(gè)請(qǐng)求必須獲取完整的響應(yīng)疾渣。
    上面是一種緩存分級(jí)機(jī)制的栗子篡诽,可以根據(jù)資源的更新情況進(jìn)行響應(yīng)的配置。當(dāng)然還可以有更多靈活配置榴捡。

3 基于flask實(shí)現(xiàn)

3.1 cache-control的flask實(shí)現(xiàn)

flask有一個(gè)擴(kuò)展包解決這個(gè)問題:flask-cachecontrol杈女。秉承flask的傳統(tǒng),使用的方法十分簡(jiǎn)單(看看代碼也好)吊圾。

from flask.ext.cachecontrol import (
    FlaskCacheControl,
    cache,
    cache_for,
    dont_cache)
flask_cache_control = FlaskCacheControl()
flask_cache_control.init_app(app)

@app.route('/')
@cache_for(hours=3)
def index_view():
    return render_template('index_template')

@app.route('/stats')
@cache(max_age=3600, public=True)
def stats_view():
    return render_template('stats_template')

@app.route('/dashboard')
@dont_cache()
def dashboard_view():
    return render_template('dashboard_template')

它簡(jiǎn)化為了三個(gè)場(chǎng)景达椰,將相關(guān)的配置都自動(dòng)在響應(yīng)包中添加。例如项乒,采用cache(max_age=3, public=False)的修飾器砰碴,返回的緩存頭包括了幾個(gè)配置參數(shù)。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 1804
Cache-Control: proxy-revalidate, no-cache, no-store, must-revalidate, max-age=0
Server: Werkzeug/0.10.4 Python/2.7.10
Date: Fri, 05 Aug 2016 03:51:28 GMT

3.2 ETag/Last-Modified的flask實(shí)現(xiàn)

ETag沒有flask擴(kuò)展包板丽,這里有一篇官方的文章介紹實(shí)現(xiàn)方法。對(duì)方法總結(jié)一下:

  • 給flask.response.set_etag()做一個(gè)猴子補(bǔ)冻媚帷(Monkeypatching)埃碱。
  • 猴子補(bǔ)丁的內(nèi)容為,校驗(yàn)請(qǐng)求包的“IF-MATCH”與“IF-NONE-MATCH”信息(即請(qǐng)求包的ETag字段)酥泞,如果不合法則直接返回錯(cuò)誤砚殿;如果合法,則執(zhí)行校驗(yàn)etag芝囤,將本次新生成的etag碼與請(qǐng)求包中的“IF-NONE-MATCH”碼相匹配似炎,則拋出“NotModified”異常(執(zhí)行304狀態(tài)碼及空包返回),如果不匹配悯姊,則進(jìn)行全數(shù)據(jù)返回且包含了新的ETag信息羡藐。
_old_set_etag = werkzeug.ETagResponseMixin.set_etag
@functools.wraps(werkzeug.ETagResponseMixin.set_etag)
def _new_set_etag(self, etag, weak=False):
    # only check the first time through; when called twice
    # we're modifying
    if (hasattr(flask.g, 'condtnl_etags_start') and
                               flask.g.condtnl_etags_start):
        if flask.request.method in ('PUT', 'DELETE', 'PATCH'):
            if not flask.request.if_match:
                raise PreconditionRequired
            if etag not in flask.request.if_match:
                flask.abort(412)
        elif (flask.request.method == 'GET' and
              flask.request.if_none_match and
              etag in flask.request.if_none_match):
            raise NotModified
        flask.g.condtnl_etags_start = False
    _old_set_etag(self, etag, weak)
werkzeug.ETagResponseMixin.set_etag = _new_set_etag
  • 校驗(yàn)ETag的行為在API的響應(yīng)代碼中執(zhí)行。
app = flask.Flask(__name__)
d = {'a': 'This is "a".\n', 'b': 'This is "b".\n'}
@app.route('/<path>',
           methods = ['GET', 'PUT', 'DELETE', 'PATCH'])
@conditional
def view(path):
    try:
        # SHA1 should generate well-behaved etags
        etag = hashlib.sha1(d[path]).hexdigest()
        if flask.request.method == 'GET':
            response = flask.make_response(d[path])
            response.set_etag(etag)
        else:
            response = flask.Response(status=204)
            del response.headers['content-type']
            response.set_etag(etag)
            if flask.request.method == 'DELETE':
                del d[path]
                del response.headers['etag']
            else:
                if flask.request.method == 'PUT':
                    d[path] = flask.request.data
                else: # (PATCH)
                    # lame PATCH technique
                    d[path] += flask.request.data
             response.set_etag(hashlib.sha1(d[path])
                                      .hexdigest())
        return response
    except KeyError:
        flask.abort(404)
app.run()

4 總結(jié)一下

緩存是一個(gè)減緩服務(wù)端壓力的手段悯许。對(duì)于一些很少改變的且不敏感的資源仆嗦,可以用開放式緩存,讓CDN等中間環(huán)節(jié)也幫我們存信息先壕。而對(duì)于一些少改變且稍為敏感的資源瘩扼,則可以使用私有式緩存,讓客戶端瀏覽器執(zhí)行緩存垃僚。甚至于更新很頻繁的還可設(shè)置為ETag校驗(yàn)或者數(shù)據(jù)十分敏感集绰,不能緩存的也有no-store機(jī)制。

采用ETag可能是比較折衷的辦法谆棺,在減緩帶寬壓力上十分有效栽燕,但在減緩服務(wù)器計(jì)算壓力(甚至數(shù)據(jù)庫(kù)壓力)上仍然沒有太大意義(ETag要求服務(wù)端先獲取了數(shù)據(jù)之后,再生成ETag,再用ETag與請(qǐng)求包的ETag驗(yàn)證)纫谅。

參考:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
http://www.tuicool.com/articles/YBbeM33
https://github.com/twiebe/Flask-CacheControl
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn
http://blog.csdn.net/salmonellavaccine/article/details/42734183
http://flask.pocoo.org/snippets/95/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炫贤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子付秕,更是在濱河造成了極大的恐慌兰珍,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件询吴,死亡現(xiàn)場(chǎng)離奇詭異掠河,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)猛计,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門唠摹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奉瘤,你說我怎么就攤上這事勾拉。” “怎么了盗温?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵藕赞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我卖局,道長(zhǎng)斧蜕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任砚偶,我火速辦了婚禮批销,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘染坯。我一直安慰自己均芽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布酒请。 她就那樣靜靜地躺著骡技,像睡著了一般。 火紅的嫁衣襯著肌膚如雪羞反。 梳的紋絲不亂的頭發(fā)上布朦,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音昼窗,去河邊找鬼是趴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛澄惊,可吹牛的內(nèi)容都是我干的唆途。 我是一名探鬼主播富雅,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼肛搬!你這毒婦竟也來了没佑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤温赔,失蹤者是張志新(化名)和其女友劉穎蛤奢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陶贼,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啤贩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拜秧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹屹。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枉氮,靈堂內(nèi)的尸體忽然破棺而出志衍,到底是詐尸還是另有隱情,我是刑警寧澤聊替,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布足画,位于F島的核電站,受9級(jí)特大地震影響佃牛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜医舆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一俘侠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔬将,春花似錦爷速、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至毙石,卻和暖如春廉沮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徐矩。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工滞时, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滤灯。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓坪稽,卻偏偏與公主長(zhǎng)得像曼玩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窒百,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 淺談瀏覽器Http的緩存機(jī)制 ? ? ? ? ? ? ? ? 針對(duì)瀏覽器的http緩存的分析也算是老生常談了黍判,每隔...
    meng_philip123閱讀 1,008評(píng)論 0 10
  • 網(wǎng)絡(luò)特有的延遲以及數(shù)據(jù)傳輸?shù)某杀荆萍s互聯(lián)網(wǎng)快速獲取Web資源篙梢。為此顷帖,HTTP協(xié)議引入緩存以空間換時(shí)間,使瀏覽器緩...
    大頭8086閱讀 3,066評(píng)論 2 12
  • 針對(duì)瀏覽器的http緩存的分析也算是老生常談了庭猩,每隔一段時(shí)間就會(huì)冒出一篇不錯(cuò)的文章窟她,其原理也是各大公司面試時(shí)幾乎必...
    全端玩法閱讀 877評(píng)論 0 9
  • 針對(duì)瀏覽器的http緩存的分析也算是老生常談了,每隔一段時(shí)間就會(huì)冒出一篇不錯(cuò)的文章蔼水,其原理也是各大公司面試時(shí)幾乎必...
    單純的土豆閱讀 387評(píng)論 0 2
  • 本文內(nèi)容大多參考《圖解HTTP》一書 一. 認(rèn)識(shí)代理服務(wù)器 所以講緩存為什么要先扯代理服務(wù)器震糖?別急,讓我們看一下一...
    流光號(hào)船長(zhǎng)閱讀 1,921評(píng)論 0 10