淺談瀏覽器http的緩存機(jī)制

針對瀏覽器的http緩存的分析也算是老生常談了颓遏,每隔一段時間就會冒出一篇不錯的文章鸠删,其原理也是各大公司面試時幾乎必考的問題怯屉。

之所以還寫一篇這樣的文章易阳,是因為近期都在搞新技術(shù)附较,想“回歸”下基礎(chǔ),也希望盡量總結(jié)的更詳盡些潦俺。

那么你是否還需要閱讀本篇文章呢拒课?可以試著回答下面這個問題:

我們在訪問百度首頁的時候,會發(fā)現(xiàn)不管怎么刷新頁面事示,靜態(tài)資源基本都是返回 200(from cache):

隨便點開一個靜態(tài)資源是醬的:

哎喲有Response報頭數(shù)據(jù)呢早像,看來服務(wù)器也正常返回了etag什么鬼的應(yīng)有盡有,那狀態(tài)200不是應(yīng)該對應(yīng)的非緩存狀態(tài)么肖爵?要from cache的話不是應(yīng)該返回304才合理么卢鹦?

難道是度娘的服務(wù)器故障了嗎?

如果你知道答案劝堪,那就可以忽略本文了冀自。

http報文中與緩存相關(guān)的首部字段

我們先來瞅一眼 RFC2616規(guī)定的47種http報文首部字段中與緩存相關(guān)的字段,事先了解一下能讓咱在心里有個底:

1. 通用首部字段(就是請求報文和響應(yīng)報文都能用上的字段)

2. 請求首部字段

3. 響應(yīng)首部字段

4. 實體首部字段

后續(xù)大體也會依次介紹它們秒啦。

場景模擬

為方便模擬各種緩存效果熬粗,我們建個非常簡單的場景。

1. 頁面文件

我們建個非常簡單的html頁面帝蒿,上面只有一個本地樣式文件和圖片:

<!DOCTYPE html>
<html>
<head>
<title>緩存測試</title>
<link rel="stylesheet" href="css/reset.css">
</head>
<body>
<h1>哥只是一個標(biāo)題</h1>
<p>[站外圖片上傳中……(18)]</p>
</body>
</html>

2. 首部字段修改

有時候一些瀏覽器會自行給請求首部加上一些字段(如chrome使用F5會強(qiáng)制加上“cache-control:max-age=0”),會覆蓋掉一些字段(比如pragma)的功能荐糜;另外有時候我們希望服務(wù)器能多/少返回一些響應(yīng)字段。

這種情況我們就希望可以手動來修改請求或響應(yīng)報文上的內(nèi)容了葛超。那么如何實現(xiàn)呢暴氏?這里我們使用Fiddler來完成任務(wù)。

在Fiddler中我們可以通過“bpu XXX”指令來攔截指定請求绣张,然后手動修改請求內(nèi)容再發(fā)給服務(wù)器答渔、修改響應(yīng)內(nèi)容再發(fā)給客戶端。

以我們的example為例侥涵,頁面文件走nginx通過 http://localhost/ 可直接訪問沼撕,所以我們直接執(zhí)行“bpu localhost”攔截所有地址中帶有該字樣的請求:

點擊被攔截的請求,可以在右欄直接修改報文內(nèi)容(上半?yún)^(qū)域是請求報文芜飘,下半?yún)^(qū)域是響應(yīng)報文)务豺,點擊黃色的“Break on Response”按鈕可以執(zhí)行下一步(把請求發(fā)給服務(wù)器),點擊綠色的按鈕“Run to Completion”可以直接完成整個請求過程:

通過這個方法我們可以很輕松地模擬出各種http緩存場景嗦明。

3. 瀏覽器的強(qiáng)制策略

如上述笼沥,當(dāng)下大多數(shù)瀏覽器在點擊刷新按鈕或按F5時會自行加上“Cache-Control:max-age=0”請求字段,所以我們先約定成俗——后文提及的“刷新”多指的是選中url地址欄并按回車鍵(這樣不會被強(qiáng)行加上Cache-Control)娶牌。

事實上有的瀏覽器還有一些更奇怪的行為奔浅,在后續(xù)我們回答文章開頭問題的時候會提到。

石器時代的緩存方式

在 http1.0 時代诗良,給客戶端設(shè)定緩存方式可通過兩個字段——“Pragma”和“Expires”來規(guī)范汹桦。雖然這兩個字段早可拋棄,但為了做http協(xié)議的向下兼容鉴裹,你還是可以看到很多網(wǎng)站依舊會帶上這兩個字段舞骆。

1. Pragma

當(dāng)該字段值為“no-cache”的時候(事實上現(xiàn)在RFC中也僅標(biāo)明該可選值),會知會客戶端不要對該資源讀緩存径荔,即每次都得向服務(wù)器發(fā)一次請求才行葛作。

Pragma屬于通用首部字段,在客戶端上使用時猖凛,常規(guī)要求我們往html上加上這段meta元標(biāo)簽(而且可能還得做些hack放到body后面去):

 <meta http-equiv="Pragma" content="no-cache">

它告訴瀏覽器每次請求頁面時都不要讀緩存赂蠢,都得往服務(wù)器發(fā)一次請求才行。

BUT!!! 事實上這種禁用緩存的形式用處很有限:

  1. 僅有IE才能識別這段meta標(biāo)簽含義辨泳,其它主流瀏覽器僅能識別“Cache-Control: no-store”的meta標(biāo)簽(見出處)虱岂。
  2. 在IE中識別到該meta標(biāo)簽含義,并不一定會在請求字段加上Pragma菠红,但的確會讓當(dāng)前頁面每次都發(fā)新請求(僅限頁面第岖,頁面上的資源則不受影響)。

做了測試后發(fā)現(xiàn)也的確如此试溯,這種客戶端定義Pragma的形式基本沒起到多少作用蔑滓。

不過如果是在響應(yīng)報文上加上該字段就不一樣了:

如上圖紅框部分是再次刷新頁面時生成的請求,這說明禁用緩存生效,預(yù)計瀏覽器在收到服務(wù)器的Pragma字段后會對資源進(jìn)行標(biāo)記键袱,禁用其緩存行為燎窘,進(jìn)而后續(xù)每次刷新頁面均能重新發(fā)出請求而不走緩存。

2. Expires

有了Pragma來禁用緩存蹄咖,自然也需要有個東西來啟用緩存和定義緩存時間褐健,對http1.0而言,Expires就是做這件事的首部字段澜汤。

Expires的值對應(yīng)一個GMT(格林尼治時間)蚜迅,比如“Mon, 22 Jul 2002 11:12:01 GMT”來告訴瀏覽器資源緩存過期時間,如果還沒過該時間點則不發(fā)請求俊抵。

在客戶端我們同樣可以使用meta標(biāo)簽來知會IE(也僅有IE能識別)頁面(同樣也只對頁面有效谁不,對頁面上的資源無效)緩存時間:

<meta http-equiv="expires" content="mon, 18 apr 2016 14:30:00 GMT">

如果希望在IE下頁面不走緩存,希望每次刷新頁面都能發(fā)新請求徽诲,那么可以把“content”里的值寫為“-1”或“0”刹帕。

注意的是該方式僅僅作為知會IE緩存時間的標(biāo)記,你并不能在請求或響應(yīng)報文中找到Expires字段馏段。

如果是在服務(wù)端報頭返回Expires字段轩拨,則在任何瀏覽器中都能正確設(shè)置資源緩存的時間:

在上圖里,緩存時間設(shè)置為一個已過期的時間點(見紅框)院喜,則刷新頁面將重新發(fā)送請求(見藍(lán)框)亡蓉。

那么如果Pragma和Expires一起上陣的話,聽誰的喷舀?我們試一試就知道了:

Cache-Control

針對上述的“Expires時間是相對服務(wù)器而言砍濒,無法保證和客戶端時間統(tǒng)一”的問題,http1.1新增了 Cache-Control 來定義緩存過期時間硫麻,若報文中同時出現(xiàn)了 Pragma爸邢、Expires 和 Cache-Control,會以 Cache-Control 為準(zhǔn)拿愧。

Cache-Control也是一個通用首部字段杠河,這意味著它能分別在請求報文和響應(yīng)報文中使用。在RFC中規(guī)范了 Cache-Control 的格式為:

"Cache-Control" ":" cache-directive

作為請求首部時浇辜,cache-directive 的可選值有:

作為響應(yīng)首部時券敌,cache-directive 的可選值有:

我們依舊可以在HTML頁面加上meta標(biāo)簽來給請求報頭加上 Cache-Control 字段:

另外 Cache-Control 允許自由組合可選值,例如:

Cache-Control: max-age=3600, must-revalidate

它意味著該資源是從原服務(wù)器上取得的柳洋,且其緩存(新鮮度)的有效時間為一小時待诅,在后續(xù)一小時內(nèi),用戶重新訪問該資源則無須發(fā)送請求熊镣。

當(dāng)然這種組合的方式也會有些限制卑雁,比如 no-cache 就不能和 max-age募书、min-fresh、max-stale 一起搭配使用测蹲。

組合的形式還能做一些瀏覽器行為不一致的兼容處理莹捡。例如在IE我們可以使用 no-cache 來防止點擊“后退”按鈕時頁面資源從緩存加載,但在 Firefox 中弛房,需要使用 no-store 才能防止歷史回退時瀏覽器不從緩存中去讀取數(shù)據(jù)道盏,故我們在響應(yīng)報頭加上如下組合值即可做兼容處理:

Cache-Control: no-cache, no-store

緩存校驗字段

上述的首部字段均能讓客戶端決定是否向服務(wù)器發(fā)送請求而柑,比如設(shè)置的緩存時間未過期文捶,那么自然直接從本地緩存取數(shù)據(jù)即可(在chrome下表現(xiàn)為200 from cache),若緩存時間過期了或資源不該直接走緩存媒咳,則會發(fā)請求到服務(wù)器去粹排。

我們現(xiàn)在要說的問題是,如果客戶端向服務(wù)器發(fā)了請求涩澡,那么是否意味著一定要讀取回該資源的整個實體內(nèi)容呢顽耳?

我們試著這么想——客戶端上某個資源保存的緩存時間過期了,但這時候其實服務(wù)器并沒有更新過這個資源妙同,如果這個資源數(shù)據(jù)量很大射富,客戶端要求服務(wù)器再把這個東西重新發(fā)一遍過來,是否非常浪費帶寬和時間呢粥帚?

答案是肯定的胰耗,那么是否有辦法讓服務(wù)器知道客戶端現(xiàn)在存有的緩存文件,其實跟自己所有的文件是一致的芒涡,然后直接告訴客戶端說“這東西你直接用緩存里的就可以了柴灯,我這邊沒更新過呢,就不再傳一次過去了”费尽。

為了讓客戶端與服務(wù)器之間能實現(xiàn)緩存文件是否更新的驗證赠群、提升緩存的復(fù)用率,Http1.1新增了幾個首部字段來做這件事情旱幼。

1. Last-Modified

服務(wù)器將資源傳遞給客戶端時查描,會將資源最后更改的時間以“Last-Modified: GMT”的形式加在實體首部上一起返回給客戶端。

客戶端會為資源標(biāo)記上該信息柏卤,下次再次請求時冬三,會把該信息附帶在請求報文中一并帶給服務(wù)器去做檢查,若傳遞的時間值與服務(wù)器上該資源最終修改時間是一致的闷旧,則說明該資源沒有被修改過长豁,直接返回304狀態(tài)碼即可。

至于傳遞標(biāo)記起來的最終修改時間的請求報文首部字段一共有兩個:

⑴ If-Modified-Since: Last-Modified-value

示例為  If-Modified-Since: Thu, 31 Mar 2016 07:07:52 GMT

該請求首部告訴服務(wù)器如果客戶端傳來的最后修改時間與服務(wù)器上的一致忙灼,則直接回送304 和響應(yīng)報頭即可匠襟。

當(dāng)前各瀏覽器均是使用的該請求首部來向服務(wù)器傳遞保存的 Last-Modified 值钝侠。

⑵ If-Unmodified-Since: Last-Modified-value

告訴服務(wù)器,若Last-Modified沒有匹配上(資源在服務(wù)端的最后更新時間改變了)酸舍,則應(yīng)當(dāng)返回412(Precondition Failed) 狀態(tài)碼給客戶端帅韧。

當(dāng)遇到下面情況時,If-Unmodified-Since 字段會被忽略:

   1. Last-Modified值對上了(資源在服務(wù)端沒有新的修改)啃勉;
   2. 服務(wù)端需返回2XX和412之外的狀態(tài)碼忽舟;
   3. 傳來的指定日期不合法

Last-Modified 說好卻也不是特別好,因為如果在服務(wù)器上淮阐,一個資源被修改了叮阅,但其實際內(nèi)容根本沒發(fā)生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)泣特。

2. ETag

為了解決上述Last-Modified可能存在的不準(zhǔn)確的問題浩姥,Http1.1還推出了 ETag 實體首部字段。

服務(wù)器會通過某種算法状您,給資源計算得出一個唯一標(biāo)志符(比如md5標(biāo)志)勒叠,在把資源響應(yīng)給客戶端的時候,會在實體首部加上“ETag: 唯一標(biāo)識符”一起返回給客戶端膏孟。

客戶端會保留該 ETag 字段眯分,并在下一次請求時將其一并帶過去給服務(wù)器。服務(wù)器只需要比較客戶端傳來的ETag跟自己服務(wù)器上該資源的ETag是否一致柒桑,就能很好地判斷資源相對客戶端而言是否被修改過了弊决。

如果服務(wù)器發(fā)現(xiàn)ETag匹配不上,那么直接以常規(guī)GET 200回包形式將新的資源(當(dāng)然也包括了新的ETag)發(fā)給客戶端幕垦;如果ETag是一致的丢氢,則直接返回304知會客戶端直接使用本地緩存即可。

那么客戶端是如何把標(biāo)記在資源上的 ETag 傳去給服務(wù)器的呢先改?請求報文中有兩個首部字段可以帶上 ETag 值:

⑴ If-None-Match: ETag-value

示例為  If-None-Match: "56fcccc8-1699"

告訴服務(wù)端如果 ETag 沒匹配上需要重發(fā)資源數(shù)據(jù)疚察,否則直接回送304 和響應(yīng)報頭即可。

當(dāng)前各瀏覽器均是使用的該請求首部來向服務(wù)器傳遞保存的 ETag 值仇奶。

⑵ If-Match: ETag-value

告訴服務(wù)器如果沒有匹配到ETag貌嫡,或者收到了“*”值而當(dāng)前并沒有該資源實體,則應(yīng)當(dāng)返回412(Precondition Failed) 狀態(tài)碼給客戶端该溯。否則服務(wù)器直接忽略該字段岛抄。

If-Match 的一個應(yīng)用場景是,客戶端走PUT方法向服務(wù)端請求上傳/更替資源狈茉,這時候可以通過 If-Match 傳遞資源的ETag夫椭。

需要注意的是,如果資源是走分布式服務(wù)器(比如CDN)存儲的情況氯庆,需要這些服務(wù)器上計算ETag唯一值的算法保持一致蹭秋,才不會導(dǎo)致明明同一個文件扰付,在服務(wù)器A和服務(wù)器B上生成的ETag卻不一樣。

如果 Last-Modified 和 ETag 同時被使用仁讨,則要求它們的驗證都必須通過才會返回304羽莺,若其中某個驗證沒通過,則服務(wù)器會按常規(guī)返回資源實體及200狀態(tài)碼。

在較新的 nginx 上默認(rèn)是同時開啟了這兩個功能的:

上圖的前三條請求是原始請求,接著的三條請求是刷新頁面后的新請求罗标,在發(fā)新請求之前我們修改了 reset.css 文件,所以它的 Last-Modified 和 ETag 均發(fā)生了改變刁卜,服務(wù)器因此返回了新的文件給客戶端(狀態(tài)值為200)。

而 dog.jpg 我們沒有做修改礁哄,其Last-Modified 和 ETag在服務(wù)端是保持不變的长酗,故服務(wù)器直接返回了304狀態(tài)碼讓客戶端直接使用緩存的 dog.jpg 即可溪北,沒有把實體內(nèi)容返回給客戶端(因為沒必要)桐绒。

緩存實踐

當(dāng)我們在一個項目上做http緩存的應(yīng)用時,我們還是會把上述提及的大多數(shù)首部字段均使用上之拨,例如使用 Expires 來兼容舊的瀏覽器茉继,使用 Cache-Control 來更精準(zhǔn)地利用緩存,然后開啟 ETag 跟 Last-Modified 功能進(jìn)一步復(fù)用緩存減少流量蚀乔。

那么這里會有一個小問題——Expires 和 Cache-Control 的值應(yīng)設(shè)置為多少合適呢烁竭?

答案是不會有過于精準(zhǔn)的值,均需要進(jìn)行按需評估吉挣。

例如頁面鏈接的請求常規(guī)是無須做長時間緩存的派撕,從而保證回退到頁面時能重新發(fā)出請求,百度首頁是用的 Cache-Control:private睬魂,騰訊首頁則是設(shè)定了60秒的緩存终吼,即 Cache-Control:max-age=60。

而靜態(tài)資源部分氯哮,特別是圖片資源际跪,通常會設(shè)定一個較長的緩存時間,而且這個時間最好是可以在客戶端靈活修改的喉钢。以騰訊的某張圖片為例:

http://i.gtimg.cn/vipstyle/vipportal/v4/img/common/logo.png?max_age=2592000

客戶端可以通過給圖片加上“max_age”的參數(shù)來定義服務(wù)器返回的緩存時間:

當(dāng)然這需要有一個前提——靜態(tài)資源能確保長時間不做改動姆打。如果一個腳本文件響應(yīng)給客戶端并做了長時間的緩存,而服務(wù)端在近期修改了該文件的話肠虽,緩存了此腳本的客戶端將無法及時獲得新的數(shù)據(jù)幔戏。

解決該困擾的辦法也簡單——把服務(wù)側(cè)ETag的那一套也搬到前端來用——頁面的靜態(tài)資源以版本形式發(fā)布,常用的方法是在文件名或參數(shù)帶上一串md5或時間標(biāo)記符:

 1  https://#/hm.js?e23800c454aa573c0ccb16b52665ac26
 2  http://tb1.bdstatic.com/tb/_/tbean_safe_ajax_94e7ca2.js
 3  http://img1.gtimg.com/ninja/2/2016/04/ninja145972803357449.jpg

如果文件被修改了税课,才更改其標(biāo)記符內(nèi)容闲延,這樣能確北海客戶端能及時從服務(wù)器收取到新修改的文件。

關(guān)于開頭的問題

現(xiàn)在回過頭來看文章開頭的問題慨代,可能會覺得答案很容易回答出來邢笙。

百度首頁的資源在刷新后實際沒有發(fā)送任何請求,因為 Cache-Control 定義的緩存時間段還沒到期侍匙。在Chrome中即使沒發(fā)送請求氮惯,但只要從本地的緩存中取,都會在Network面板顯示一條狀態(tài)為200且注明“from cache”的偽請求想暗,其Response內(nèi)容只是上一次回包留下的數(shù)據(jù)妇汗。

然而這并不是問題的全部答案,我們前面提到過说莫,在Chrome中如果點擊“刷新”按鈕杨箭,Chrome會強(qiáng)制給所有資源加上“Cache-Control: max-age=0”的請求首部并向服務(wù)器發(fā)送驗證請求的,而在文章開頭的動圖中储狭,我們的確點擊了“刷新”按鈕互婿,卻不見瀏覽器發(fā)去新請求(并返回304)。

關(guān)于這個問題其實在組內(nèi)跟小伙伴們討論過辽狈,通過Fiddler抓包發(fā)現(xiàn)慈参,如果關(guān)閉Chrome的開發(fā)者面板再點擊“刷新”按鈕,瀏覽器是會按預(yù)期發(fā)送驗證請求且接收返回的304響應(yīng)的刮萌,另外這個奇怪的情況在不同的網(wǎng)站甚至不同的電腦下出現(xiàn)頻率都不一致驮配,所以暫時將其歸咎于瀏覽器的怪異反應(yīng)。

那么有這么一個問題——是否有辦法在瀏覽器點擊“刷新”按鈕的時候不讓瀏覽器去發(fā)新的驗證請求呢着茸?

辦法還是有的壮锻,就是不怎么實用——在頁面加載完畢后通過腳本動態(tài)地添加資源:

 $(window).load(function() {
     var bg='http://img.infinitynewtab.com/wallpaper/100.jpg';
     setTimeout(function() {  //setTimeout是必須的
     $('#bgOut').css('background-image', 'url('+bg+')');
     },0);
 });

出處來自知乎,更具體的解釋可以去看看涮阔。

其它相關(guān)的首部字段

事實上較常用和重要的緩存相關(guān)字段我們都介紹完了猜绣,這里順帶講講幾個跟緩存有關(guān)系,但沒那么主要的響應(yīng)首部字段澎语。

1. Vary

“vary”本身是“變化”的意思途事,而在http報文中更趨于是“vary from”(與。擅羞。尸变。不同)的含義,它表示服務(wù)端會以什么基準(zhǔn)字段來區(qū)分减俏、篩選緩存版本召烂。

我們先考慮這么一個問題——在服務(wù)端有著這么一個地址,如果是IE用戶則返回針對IE開發(fā)的內(nèi)容娃承,否則返回另一個主流瀏覽器版本的內(nèi)容奏夫。這很簡單怕篷,服務(wù)端獲取到請求的 User-Agent 字段做處理即可。但是用戶請求的是代理服務(wù)器而非原服務(wù)器酗昼,且代理服務(wù)器如果直接把緩存的IE版本資源發(fā)給了非IE的客戶端廊谓,這就出問題了。

因此 Vary 便是著手處理該問題的首部字段麻削,我們可以在響應(yīng)報文加上:

 Vary: User-Agent

便能知會代理服務(wù)器需要以 User-Agent 這個請求首部字段來區(qū)別緩存版本蒸痹,防止傳遞給客戶端的緩存不正確。

Vary 也接受條件組合的形式:

 Vary: User-Agent, Accept-Encoding

這意味著服務(wù)器應(yīng)以 User-Agent 和 Accept-Encoding 兩個請求首部字段來區(qū)分緩存版本呛哟。

2. Date 和 Age

HTTP并沒有提供某種方法來幫用戶區(qū)分其收到的資源是否命中了代理服務(wù)器的緩存叠荠,但在客戶端我們可以通過計算響應(yīng)報文中的 Date 和 Age 字段來得到答案。

Date 理所當(dāng)然是原服務(wù)器發(fā)送該資源響應(yīng)報文的時間(GMT格式)扫责,如果你發(fā)現(xiàn) Date 的時間與“當(dāng)前時間”差別較大榛鼎,或者連續(xù)F5刷新發(fā)現(xiàn) Date 的值都沒變化,則說明你當(dāng)前請求是命中了代理服務(wù)器的緩存鳖孤。

上述的“當(dāng)前時間”自然是相對于原服務(wù)器而言的時間者娱,那么如何獲悉原服務(wù)器的當(dāng)前時間呢?

常規(guī)從頁面地址請求的響應(yīng)報文中可獲得淌铐,以博客園首頁為例:

每次你刷新頁面肺然,瀏覽器都會重新發(fā)出這條url的請求,你會發(fā)現(xiàn)其 Date 值是不斷變化的腿准,這說明該鏈接沒有命中緩存,都是從原服務(wù)器返回過來的數(shù)據(jù)拾碌。

因此我們可以拿頁面上其它靜態(tài)資源請求回包中的 Date 與其進(jìn)行對比吐葱,若靜態(tài)資源的 Date 早于原服務(wù)端時間,則說明命中了代理服務(wù)器緩存校翔。

通常還滿足這么個條件:

 靜態(tài)資源Age + 靜態(tài)資源Date = 原服務(wù)端Date

這里的 Age 也是響應(yīng)報文中的首部字段弟跑,它表示該文件在代理服務(wù)器中存在的時間(秒),如文件被修改或替換防症,Age會重新由0開始累計孟辑。

我們在上面那張博客園首頁報文截圖的同個場景下,看看某個文件(jQuery.js)命中代理服務(wù)器緩存的回包數(shù)據(jù):

會發(fā)現(xiàn)它滿足我們上述的規(guī)則:

//return true
new Date('Mon, 04 Apr 2016 07:03:17 GMT')/1000 == new Date('Sat, 19 Dec 2015 01:29:14 GMT')/1000 + 9264843

不過這條規(guī)則也不一定準(zhǔn)確蔫敲,特別是當(dāng)原服務(wù)器經(jīng)常修改系統(tǒng)時間的情況下饲嗽。

關(guān)于http緩存原理的知識就整理到這,希望能讓你有所收獲奈嘿,共勉~

轉(zhuǎn)自http://www.cnblogs.com/vajoy/p/5341664.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末貌虾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子裙犹,更是在濱河造成了極大的恐慌尽狠,老刑警劉巖衔憨,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異袄膏,居然都是意外死亡践图,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門沉馆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來平项,“玉大人,你說我怎么就攤上這事悍及∶銎埃” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵心赶,是天一觀的道長扣讼。 經(jīng)常有香客問我,道長缨叫,這世上最難降的妖魔是什么椭符? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮耻姥,結(jié)果婚禮上销钝,老公的妹妹穿的比我還像新娘。我一直安慰自己琐簇,他們只是感情好蒸健,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著婉商,像睡著了一般似忧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丈秩,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天盯捌,我揣著相機(jī)與錄音,去河邊找鬼蘑秽。 笑死饺著,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肠牲。 我是一名探鬼主播幼衰,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼埂材!你這毒婦竟也來了塑顺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎严拒,沒想到半個月后扬绪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡裤唠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年挤牛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片种蘸。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡墓赴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出航瞭,到底是詐尸還是另有隱情诫硕,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布刊侯,位于F島的核電站章办,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏滨彻。R本人自食惡果不足惜藕届,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亭饵。 院中可真熱鬧休偶,春花似錦、人聲如沸辜羊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽只冻。三九已至庇麦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喜德,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工垮媒, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留舍悯,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓睡雇,卻偏偏與公主長得像萌衬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子它抱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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