【小白學爬蟲筆記】HTTP0.9 HTTP1.0 HTTP1.1 HTTP/2

一、浮光掠影

1. HTTP 0.9????只接受 GET 一種請求方法则吟,沒有在通訊中指定版本號槐臀,不支持請求頭。不支持 POST 方法氓仲,所以客戶端無法向服務器傳遞太多信息水慨。

2. HTTP 1.0 RFC 1945 60頁 1996年

3. HTTP 1.1 RFC 2616 176頁 1999年

4. HTTP/2 原名 HTTP/2.0? ?RFC 7540/7541? 2015年5月15日

網(wǎng)站首頁加載需要下載的數(shù)據(jù)量增加,超過1.9MB敬扛,平均每個頁面為完成顯示和渲染所需下載的資源數(shù)超過100個

二晰洒、HTTP協(xié)議特點

1)采用請求/響應模型, 支持客戶/服務器模式啥箭。

2)簡單快速:客戶向服務器請求服務時谍珊,最簡單的方法只需傳送請求方法和路徑。請求方法常用的有GET急侥、HEAD砌滞、POST、OPTIONS坏怪。每種方法規(guī)定了客戶與服務器聯(lián)系的類型不同贝润。由于HTTP協(xié)議簡單,使得HTTP服務器的程序規(guī)模小铝宵,因而通信速度很快打掘。

3)靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對象。正在傳輸?shù)念愋陀蒀ontent-Type加以標記鹏秋,示例:

text/html

text/javascript;charset=utf-8

img/png

video/mp4

application/json;charset=utf-8

application-x-www-form-urlencoded

等等尊蚁,二進制的content-type如何?會在什么場景用到拼岳?

4)無連接:?無連接的含義是限制每次連接只處理一個請求枝誊,即連接無法復用。在持久連接或者HTTP pipelining出現(xiàn)之前惜纸,每個連接的獲取都需要創(chuàng)建一個獨立的TCP連接。每次請求都要經(jīng)歷三次握手和慢啟動绝骚,服務器處理完客戶的請求耐版,并收到客戶的應答后,即斷開連接压汪。最初HTTP協(xié)議如此粪牲,后有所改進。

HTTP 0.9:非持續(xù)連接止剖,每個連接只處理一個請求響應事務腺阳,已過時落君。

HTTP 1.0:? ?默認是非持續(xù)連接,請求頭可以設置Connection:Keep-Alive亭引,可以在一定時間內復用連接绎速,具體復用時間的長短可以由服務器控制,一般在15s左右焙蚓。

HTTP 1.1 默認使用持續(xù)連接纹冤,不必為每一個WEB對象建立一個新的連接,一個連接可以傳送多個對象

HTTP/2? 多路復用(一個域只要一個TCP連接)實現(xiàn)真正的并發(fā)請求购公,降低延時萌京,提高了帶寬的利用率。


5)無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議宏浩。無狀態(tài)是指協(xié)議對于事務處理沒有記憶能力知残。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳比庄,這樣可能導致每次連接傳送的數(shù)據(jù)量增大求妹。另一方面,在服務器不需要先前信息時它的應答就較快印蔗。

三扒最、ODDS AND ENDS

1. HTTP1.0是排隊發(fā)出請求?


對于http1.0的實現(xiàn)华嘹,在第一個請求沒有收到回復之前吧趣,后續(xù)從應用層發(fā)出的請求只能排隊,請求2耙厚,3强挫,4,5只能等請求1的response回來之后才能逐個發(fā)出薛躬。網(wǎng)絡通暢的時候性能影響不大俯渤,一旦請求1的request因為什么原因沒有抵達服務器,或者response因為網(wǎng)絡阻塞沒有及時返回型宝,影響的就是所有后續(xù)請求八匠,問題就變得比較嚴重了。

2. 無狀態(tài)的改進

3.? 無連接的改變--連接的復用--保持長連接

1. Keep-Alive或者?persistent 連接

HTTP1.0 + Keep-Alive? 不肯定即否定? ? ?

如果服務器愿意為下一條請求將連接保持在打開狀態(tài)趴酣,就在響應頭中說明梨树,如果響應頭中沒有Connection:Keep-Alive ,客戶端就認為服務器不支持keep-live岖寞,會在發(fā)回響應報文后關閉連接抡四。

HTTP 1.1+ ?persistent 連接? 不否定即肯定

HTTP/1.1逐漸停止了對keep-alive連接的支持,用一種名為持久連接的改進型設計取代了它。持久連接的目的與keep-alive連接的目的相同指巡,但是工作機制更優(yōu)些淑履。HTTP/1.1就直接默認連接情況下是激活的,除非特別指明藻雪,否則HTTP/1.1假定所有的連接都是持久的秘噪。要想在事務處理結束之后將連接關閉,HTTP/1.1應用程序必須向報文中顯示地添加一個Connection:close報頭阔涉。

HTTP1.1客戶端加載在收到響應后缆娃,除非響應中包含了Connection:close首部,不然HTTP/1.1連接就仍然維持在打開狀態(tài)瑰排。但是贯要,客戶端和服務器仍然可以隨時關閉空閑的連接。

是否有這種可能椭住,防火墻檢測 TCP端口的 idle時間崇渗,超出一些限制會被關閉?

不發(fā)送Connection:close并不意味這服務器承諾永遠將連接保持在打開狀態(tài).京郑。

?Connection默認值:Keep-Alive宅广,如要關閉連接復用需顯式的設置Connection:Close。


PC端瀏覽器:? 大部分的請求在集中在一小段時間以內些举。一段時間內復用有效跟狱。

移動app:? ? 請求比較分散且時間跨度相對較大,? 從應用層尋求其它解決方案,長連接方案或者偽長連接方案户魏。

方案一:基于tcp的長連接

http短連接模式:頻繁的創(chuàng)建和銷毀連接驶臊,增加服務器壓力

基于TCP的Socket編程,自己制定協(xié)議叼丑,建立自己的長連接通道关翎,信息的上報和推送更及時。應用產品:許多移動端app鸠信,如即時通訊(IM)纵寝,淘寶等電商類app,業(yè)界成熟方案:Google 的 protobut星立。

方案二:http long-polling




客戶端在初始狀態(tài)就會發(fā)送一個polling請求到服務器爽茴,服務器并不會馬上返回業(yè)務數(shù)據(jù),而是等待有新的業(yè)務數(shù)據(jù)產生的時候再返回绰垂。所以連接會一直被保持闹啦,一旦結束馬上又會發(fā)起一個新的polling請求,如此反復辕坝,所以一直會有一個連接被保持。服務器有新的內容產生的時候荐健,并不需要等待客戶端建立一個新的連接酱畅。做法雖然簡單琳袄,但有些難題需要攻克才能實現(xiàn)穩(wěn)定可靠的業(yè)務框架:

a. 用戶增長時會增加服務器壓力

b. 移動端網(wǎng)路環(huán)境復雜,比如纺酸,wifi和4g切換窖逗,進入電梯導致網(wǎng)絡臨時中斷,這些場景如何重建監(jiān)控連接通道餐蔬?

c. 這種polling的方式穩(wěn)定性并不好碎紊,需要做好數(shù)據(jù)可靠性的保證,比如重發(fā)和ack機制樊诺。

d. polling的response有可能會被中間代理cache住仗考,要處理好業(yè)務數(shù)據(jù)的過期機制。

e. long-polling方式還有一些無法克服的缺點词爬,比如每次新的請求都會帶上重復的header信息秃嗜,還有數(shù)據(jù)通道是單向的,主動權掌握在server這邊顿膨,客戶端有新的業(yè)務請求的時候無法及時傳送锅锨。

方案三:http streaming



a. server response的響應頭:”Transfer Encoding: chunked”? 告訴客戶端后續(xù)還會有新的數(shù)據(jù)到來

b. server不會結束初始的streaming請求,long-polling會恋沃?而是持續(xù)的通過這個通道返回最新的業(yè)務數(shù)據(jù)必搞。這個數(shù)據(jù)通道也是單向的

c. streaming不會產生重復的header數(shù)據(jù)。

d.和long-polling有相同的難點之外囊咏,此外:

d.a. 有些代理服務器會等待服務器的response結束之后才會將結果推送到請求客戶端恕洲。對于streaming這種永遠不會結束的方式來說,客戶端就會一直處于等待response的過程中匆笤。

d.b. 業(yè)務數(shù)據(jù)無法按照請求來做分割研侣,所以客戶端每收到一塊數(shù)據(jù)都需要自己做協(xié)議解析,也就是說要做自己的協(xié)議定制炮捧。


方案四:web socket

a. 基于tcp協(xié)議庶诡,提供雙向數(shù)據(jù)通道

b. 傳統(tǒng)的tcp socket基于字節(jié)流

c. WebSocket優(yōu)勢:message,又提供了傳統(tǒng)的http所缺少的長連接功能

d. 2010年才起草咆课,并非所有的瀏覽器支持末誓。各大瀏覽器廠商最新的版本都提供了支持。

e.與HTML5的Server-Sent對比

Web應用已經(jīng)使用了各種從服務器上輪詢資源的方法來持續(xù)地更新頁面书蚪,HTML5的EventSource對象和Server-Sent事件能通過瀏覽器端的JavaScript代碼打開一個服務端連接客戶端的單向通道喇澡,服務端可以使用這個寫通道來發(fā)送數(shù)據(jù),這樣能節(jié)省了HTTP創(chuàng)建多個輪詢請求的消耗殊校。

這種方式比HTML的WebSocket更高效晴玖,WebSocket的使用場景是,當有許多客戶端和服務端的交互的時候(比如消息或者游戲),在全雙工連接上建立一個雙向通道呕屎。

使用HTML5服務端發(fā)送事件,這個技術是基于具體的技術實現(xiàn)的让簿,如果網(wǎng)站當前是使用其他的Ajax或者Comet技術來輪詢的,轉變成Server-Sent事件需要重構網(wǎng)站的Javascript代碼秀睛。

3.線頭阻塞head of line blocking的改進

HTTP 1.0 必須是有響應了才能發(fā)下一個請求

HTTP Pipelining:是將多個HTTP請求放到一個TCP連接中一一發(fā)送尔当,而在發(fā)送過程中不需要等待服務器對前一個請求的響應;但是客戶端還是按照發(fā)送請求的順序接收響應蹂安。

HTTP Pipelining只能適用于http1.1椭迎,一般來說,支持http1.1的server都要求支持pipelining田盈。



請求2畜号,3,4缠黍,5不用等請求1的response返回之后才發(fā)出弄兜,而是幾乎在同一時間把request發(fā)向了服務器。2瓷式,3替饿,4,5及所有后續(xù)共用該連接的請求節(jié)約了等待的時間贸典,極大的降低了整體延遲视卢。

舉個例子,超市收銀臺或銀行柜臺排隊廊驼,你不知道前面的顧客是干脆利索還是磨蹭到世界末日据过,收銀員/柜員(服務器)是要按照順序處理請求,如果前面一個顧客非常磨蹭(請求非常耗時)妒挎,后續(xù)請求都會受到影響绳锅,即所謂的線頭阻塞(Head of line of blocking)。

只有冪等的請求(GET酝掩,HEAD)能使用pipelining鳞芙,非冪等請求比如POST不能使用,因為請求之間可能會存在先后依賴關系期虾。

head of line blocking并沒有完全得到解決原朝,server的response還是要求依次返回,遵循FIFO(first in first out)原則镶苞。也就是說如果請求1的response沒有回來喳坠,2,3茂蚓,4壕鹉,5的response也不會被送回來剃幌。

絕大部分的http代理服務器不支持pipelining。

和不支持pipelining的老服務器協(xié)商有問題御板。

可能會導致新的Front of queue blocking問題锥忿。

正是因為有這么多的問題,各大瀏覽器廠商要么是根本就不支持pipelining怠肋,要么就是默認關掉了pipelining機制,而且啟用的條件十分苛刻淹朋◇细鳎可以參考chrome對于pipeling的問題描述

4.其他的延遲解決小技巧:

提高HTTP1.X協(xié)議傳輸速度的技巧:

· Spriting(圖片合并)

a.多個小圖片合并到一張大圖础芍,原先本需要多個小請求杈抢,現(xiàn)只需一個大圖請求

b. 再利用js或者css取出其中的小圖

c. 優(yōu)點:請求數(shù)減少,延遲降低仑性。

d. 弊端:文件的粒度變大

只需小圖惶楼,卻不得不下載整張大圖

cache處理不便,一張小圖過期卻必須從服務器下載完整的大圖诊杆,浪費流量歼捐。

· Inlining(內容內嵌)

HTML的標準是使用鏈接來加載外部資源,這使得更容易在服務器上(或者在CDN上)操作更新這些資源晨汹,而不是在每個頁面上修改更新這些資源豹储,這種模式也使得瀏覽器能從本地緩存而不是服務器上獲取資源。

但是對還沒有緩存到瀏覽器localStorage的資源來說淘这,這種模式對網(wǎng)站的性能有負面的影響剥扣,一般來說,一個頁面需要幾十個單獨的請求來獲取資源從而渲染頁面铝穷。

從性能的角度來說钠怯,如果一個資源沒有很高的被緩存的幾率的話,最好把它嵌入到頁面的HTML中(叫inlining)曙聂,而不是使用鏈接外部晦炊,腳本和樣式是支持內嵌到HTML中的,但是圖片和其他的二進制資源其實也是可以通過內嵌包含base64編碼的文本來嵌入到HTML中的筹陵。

如一個網(wǎng)頁有一張背景圖刽锤,可以通過如下代碼嵌入:

background: url(data:image/png;base64,)

data部分是base64編碼之后的字節(jié)碼,避免了一次多余的http請求朦佩。

內嵌的缺點是頁面的大小會變得非常大并思,所以對于Web應用來說,關鍵的是能夠跟蹤分析這個資源什么時候需要從服務端獲取语稠,什么時候已經(jīng)緩存到客戶端了宋彼。

另外弄砍,在第一次請求資源后必須能夠使用代碼在客戶端緩存資源,因此输涕,在移動設備上音婶,使用HTML5 localStorage能很好地做到內嵌。

由于不知道用戶是否已經(jīng)訪問過這個頁面了莱坎,所以需要網(wǎng)站有機制能生成不同版本的頁面衣式。

優(yōu)點:

Inlining內聯(lián)的方式,采用inline css/inline js等并入html中檐什,減少對css/js文件的請求

弊端:

內聯(lián)的方式碴卧,會讓我們的代碼變得難以維護,讓html文件變得更大乃正,代碼混合嚴重住册。

· Concatenation(文件合并)

大型網(wǎng)站現(xiàn)在前端開發(fā)交互越來越多,往往會包含大量的JavaScript文件瓮具,某些前端工具可以幫助開發(fā)人員將這些文件合并為一個大的文件荧飞,從而讓瀏覽器能只花一個請求就將其下載完,而不是發(fā)無數(shù)請求去分別下載那些瑣碎的JavaScript文件名党。弊端是如果某個頁面只需要其中一小部分代碼叹阔,也必須下載完整的那份,而文件中小小的一個改動也會造成大量數(shù)據(jù)被重新下載兑巾。

將多個js文件合并到一個大的文件里在做一些壓縮處理也可以減小延遲和傳輸?shù)臄?shù)據(jù)量条获。

但同樣也面臨著粒度變大的問題,一個小的js代碼改動會導致整個js文件被下載蒋歌。

· CDN資源多域名轉發(fā)帅掘,靜態(tài)資源分布存儲在多個域下

Domain Sharding(域名分片)

Sharding(shard是碎瓷片瓦片)

a.?

瀏覽器或者客戶端根據(jù)domain(域名)建立連接的。

最初HTTP1.1只允許一個客戶端只能對同一主機建立兩個TCP鏈接堂油,比如針對Example Domain只允許同時建立2個連接修档,但mobile.example.com被認為是另一個域名,可以再建立兩個新的連接府框。于是有些網(wǎng)站用新的主機名庶香,這樣用戶就可以與網(wǎng)站建立更多的連接拄显,從而降低載入時間。后來限制取消,客戶端很輕松地和每個主機建立6-8個連接咱士,但由于連接上限仍然存在米酬,所以網(wǎng)站還是會用更多連接來保證HTTP協(xié)議的效率骑丸,提升載入速度霎冯。

httparcgive.org15年時顯示,TOP30萬個URL中平均用40個TCP連接來顯示頁面盹牧。


b. 依此類推俩垃,再多建立幾個sub domain(子域名)励幼,增加同時可以建立的http請求數(shù),此即Domain Sharding口柳。

c. 優(yōu)點:增加連接數(shù)苹粟,受限制的請求不需要等待前面的請求完成才能發(fā)出了。一個頗具規(guī)模的網(wǎng)頁請求數(shù)超過100跃闹,使用domain sharding之后同時建立的連接數(shù)可以多到50個甚至更多嵌削。

資源文件一般不需要cookie,將這些不同的靜態(tài)資源文件分散在不同的域名服務器上辣卒,可以減小請求的size掷贾。

d. 弊端:增加了系統(tǒng)資源的消耗,由于硬件資源升級非常之快荣茫,犧牲資源消耗換取用戶寶貴的等待時間。

e. 注意: domain sharding只有在請求數(shù)非常之多的場景下才有明顯的效果,請求數(shù)也不是越多越好场靴,資源消耗是一方面啡莉,另一點是由于tcp的slow start會導致每個請求在初期都會經(jīng)歷slow start,還有tcp 三次握手旨剥,DNS查詢的延遲咧欣。這一部分帶來的時間損耗和請求排隊同樣重要,到底怎么去平衡這二者就需要取一個可靠的連接數(shù)中間值轨帜,這個值的最終確定要通過反復的測試魄咕。

f. 移動端瀏覽器場景建議不使用domain sharding,具體細節(jié)參考這篇文章蚌父。

CDN資源多域名轉發(fā)

小結:

前面回顧了HTTP 1.0 HTTP 1.1? ? 的三類問題和解決方式:

1. 無狀態(tài)(cookies)

2. 無連接·連接的復用·連接的保持

?a. Connection:Keep-Alive在HTTP 1.0 和 HTTP 1.1中的區(qū)別

HTTP1.0 + Keep-Alive? 不肯定即否定?

HTTP 1.1+ ?persistent 連接? 不否定即肯定

b. http long-polling

? ? streaming? ? ? ? ? ?

c.? ? ??·??WebSocket哮兰,是標準長連接,按說不屬于HTTP協(xié)議苟弛,可以看成是全新的TCP協(xié)議喝滞,但是建立的前期還是會通過HTTP和服務器通信,有些人將其劃分為HTTP的補充協(xié)議膏秫。它是全雙工的右遭,這個協(xié)議主要的好處在于服務器可以主動推送數(shù)據(jù),在HTTP下缤削,服務器無法主動推送窘哈,都是請求/響應模式。

d.? ?·??移動端基于TCP的Socket編程亭敢,自定義協(xié)議滚婉,建立自己的長連接通道

3. 線頭阻塞、延遲

前面無連接的問題看似緩和了吨拗,但是又產生了線頭阻塞满哪,延遲等的問題

· 線頭阻塞·pipelining(管道化)

HTTP 1.0? ? ? 有響應之后方能發(fā)送下一個請求

HTTP 1.1? ? ? pipeling只能用于HTTP 1.1 發(fā)請求可以不排隊婿斥,但是處理請求仍排隊,且大部分服務器不支持pipeling,即便支持哨鸭,條件嚴格

延遲·HTTP1.X協(xié)議傳輸速度提高·帶著鐐銬跳舞

·減少請求次數(shù)·小合大:Spriting(圖片合并)民宿、Concatenation(文件合并)

·不易緩存文件·減少css/js文件請求次數(shù):Inlining(內容內嵌)

·增加連接數(shù):Domain Sharding(域名分片)


應聘者API·小結

HTTP1.X傳輸優(yōu)化方法

1、多個資源合并成一個請求連接像鸡,如前端Spriting雪碧圖活鹰,JS/CSS壓縮成一個文件等

2、Inlining內聯(lián)的方式只估,采用inline css/inline js等并入html中志群,減少對css/js文件的請求

3、CDN資源多域名轉發(fā)蛔钙,靜態(tài)資源分布存儲在多個域下锌云。

以上三種三種方法雖然能使HTTP1.X協(xié)議傳輸速度提高,但也有對應的不足吁脱。

如雪碧圖桑涎,將多個小圖合并成一張大圖,降低多張小圖請求的高延遲兼贡,但是如果我只想要兩個icon小圖攻冷,卻需要加載一整張大圖,就會造成資源冗余遍希。合并的JS/CSS文件也有類似的問題等曼。

內聯(lián)的方式,會讓我們的代碼變得難以維護凿蒜,讓html文件變得更大禁谦,代碼混合嚴重。

多域名下可緩解Max-Connection篙程,但不同域會讓Cookie信息無法彼此共享枷畏。


· 上述是HTTP 1.X的一些痛點,于是催生出了新一代的HTTP協(xié)議 HTTP/2

·? HTTP/2起源于SPDY虱饿, SPDY是由Google牽頭開發(fā)

HTTP1.0和1.1雖然存在這么多問題拥诡,業(yè)界也想出了各種優(yōu)化的手段,但這些方法手段都是在嘗試繞開協(xié)議本身的缺陷氮发,都有種隔靴搔癢渴肉,治標不治本的感覺。直到2012年google如一聲驚雷提出了SPDY的方案爽冕,大家才開始從正面看待和解決老版本http協(xié)議本身的問題仇祭,這也直接加速了http2.0的誕生。實際上颈畸,HTTP2.0是以SPDY為原型進行討論和標準化的乌奇。為了給HTTP2.0讓路没讲,google已決定在2016年不再繼續(xù)支持SPDY開發(fā),但在HTTP2.0出生之前礁苗,SPDY已經(jīng)有了相當規(guī)模的應用爬凑,作為一個過渡方案恐怕在還將一段時間內繼續(xù)存在。現(xiàn)在不少app客戶端和server都已經(jīng)使用了SPDY來提升體驗试伙,HTTP2.0在老的設備和系統(tǒng)上還無法使用(iOS系統(tǒng)只有在iOS9+上才支持)嘁信,所以可以預見未來幾年SPDY將和http2.0共同服務的情況。

https://imququ.com/post/http2-resource.html

三. 開拓者SPDY

1 SPDY的目標

HTTP 1.x的痛點疏叨, 歸結起來是延遲和安全性潘靖。

SPDY的目標在一開始就是瞄準HTTP 1.X的痛點

HTTP 是明文協(xié)議,其安全性一直被業(yè)界詬病蚤蔓,不過這是另一個大的話題卦溢。

如果以降低延遲為目標,應用層的HTTP和傳輸層的TCP都是都有調整的空間秀又,不過TCP作為更底層協(xié)議存在已達數(shù)十年之久既绕,其實現(xiàn)已深植全球的網(wǎng)絡基礎設施當中,如果要動必然傷經(jīng)動骨涮坐,業(yè)界響應度必然不高,所以SPDY的手術刀對準的是HTTP誓军。

降低延遲袱讹,客戶端的單連接單請求,server的FIFO響應隊列都是延遲的大頭昵时。

http最初設計都是客戶端發(fā)起請求捷雕,然后server響應,server無法主動push內容到客戶端壹甥。

壓縮HTTP header救巷,HTTP 1.x的header越來越膨脹,cookie和user agent很容易讓header的size增至1kb大小句柠,甚至更多浦译。而且由于HTTP的無狀態(tài)特性,header必須每次request都重復攜帶溯职,很浪費流量精盅。

為了增加業(yè)界響應的可能性,Google一開始就避開了從傳輸層動手谜酒,而且打算利用開源社區(qū)的力量以提高擴散的力度叹俏,對于協(xié)議使用者來說,也只需要在請求的header里設置user agent僻族,然后在server端做好支持即可粘驰,極大的降低了部署的難度屡谐。SPDY的設計如下:



SPDY位于HTTP之下,TCP和SSL之上蝌数,這樣可以輕松兼容老版本的HTTP協(xié)議(將HTTP 1.x的內容封裝成一種新的frame格式)愕掏,同時可以使用已有的SSL功能。SPDY的功能可以分為基礎功能和高級功能兩部分籽前,基礎功能默認啟用亭珍,高級功能需要手動啟用。

2 SPDY基礎功能

多路復用(multiplexing)枝哄。多路復用通過多個請求stream共享一個tcp連接的方式肄梨,解決了HTTP1.x holb(head of line blocking)的問題,降低了延遲同時提高了帶寬的利用率挠锥。

請求優(yōu)先級(request prioritization)众羡。多路復用帶來一個新的問題是,在連接共享的基礎之上有可能會導致關鍵請求被阻塞蓖租。SPDY允許給每個request設置優(yōu)先級粱侣,這樣重要的請求就會優(yōu)先得到響應。比如瀏覽器加載首頁蓖宦,首頁的html內容應該優(yōu)先展示齐婴,之后才是各種靜態(tài)資源文件,腳本文件等加載稠茂,這樣可以保證用戶能第一時間看到網(wǎng)頁內容柠偶。

header壓縮。前面提到過幾次HTTP1.x的header很多時候都是重復多余的睬关。選擇合適的壓縮算法可以減小包的大小和數(shù)量诱担。SPDY對header的壓縮率可以達到80%以上,低帶寬環(huán)境下效果很大电爹。

2 SPDY高級功能

server推送(server push)蔫仙。HTTP1.x只能由客戶端發(fā)起請求,然后服務器被動的發(fā)送response丐箩。開啟server push之后摇邦,server通過X-Associated-Content header(X-開頭的header都屬于非標準的,自定義header)告知客戶端會有新的內容推送過來雏蛮。在用戶第一次打開網(wǎng)站首頁的時候涎嚼,server將資源主動推送過來可以極大的提升用戶體驗。

server暗示(server hint)挑秉。和server push不同的是法梯,server hint并不會主動推送內容,只是告訴有新的內容產生,內容的下載還是需要客戶端主動發(fā)起請求立哑。server hint通過X-Subresources header來通知夜惭,一般應用場景是客戶端需要先查詢server狀態(tài),然后再下載資源铛绰,可以節(jié)約一次查詢請求诈茧。

3 SPDY的成績

SPDY的成績可以用google官方的一個數(shù)字來說明:頁面加載時間相比于HTTP 1.x減少了64%。而且各大瀏覽器廠商在SPDY誕生之后的1年多里都陸續(xù)支持了SPDY捂掰,不少大廠app和server端框架也都將SPDY應用到了線上的產品當中敢会。

google的官網(wǎng)也給出了他們自己做的一份測試數(shù)據(jù)。測試對象是25個訪問量排名靠前的網(wǎng)站首頁这嚣,家用網(wǎng)絡%1的丟包率鸥昏,每個網(wǎng)站測試10次取平均值。結果如下:


不開啟ssl的時候提升在 27% - 60%姐帚,開啟之后為39% - 55%吏垮。 這份測試結果有兩點值得特別注意:

3.1 連接數(shù)的選擇

連接:基于域名建立,另一種選擇是罐旗,不做區(qū)分所有子域名都共享一個連接膳汪。

以上google的測試結果顯示單一連接性能高于多域名連接方式。之所以出現(xiàn)這種情況是由于網(wǎng)頁所有的資源請求并不是同一時間發(fā)出九秀,后續(xù)發(fā)出的子域名請求如果能復用之前的tcp連接當然性能更好遗嗽。實際應用場景下應該也是單連接共享模式表現(xiàn)好。

3.2 帶寬的影響

測試基于兩種帶寬環(huán)境鼓蜒,一慢一快媳谁。

網(wǎng)速快的環(huán)境下對減小延遲的提升更大,單連接模式下可以提升至60%友酱。原因也比較簡單,帶寬越大柔纵,復用連接的請求完成越快缔杉,由于三次握手和慢啟動導致的延遲損耗就變得更明顯。

出了連接模式和帶寬之外搁料,丟包率和RTT也是需要測試的參數(shù)或详。SPDY對header的壓縮有80%以上,整體包大小能減少大概40%郭计,發(fā)送的包越少霸琴,自然受丟包率影響也就越小,所以丟包率大的惡劣環(huán)境下SPDY反而更能提升體驗昭伸。下圖是受丟包率影響的測試結果梧乘,丟包率超過2.5%之后就沒有提升了:

[圖8]

RTT越大,延遲會越大,在高RTT的場景下选调,由于SPDY的request是并發(fā)進行的夹供,所有對包的利用率更高,反而能更明顯的減小總體延遲仁堪。測試結果如下:

<img src="https://pic3.zhimg.com/0e76aabb96a1d492433aa7003975bda6_b.png" data-rawwidth="1170" data-rawheight="450" class="origin_image zh-lightbox-thumb" width="1170" data-original="https://pic3.zhimg.com/0e76aabb96a1d492433aa7003975bda6_r.jpg">

[圖9]

SPDY從2012年誕生到2016停止維護哮洽,時間跨度對于網(wǎng)絡協(xié)議來說其實非常之短。如果HTTP2.0沒有出來弦聂,google或許能收集到更多業(yè)界產品的真實反饋和數(shù)據(jù)鸟辅,畢竟google自己的測試環(huán)境相對簡單。但SPDY也完成了自己的使命莺葫,作為一貫扮演拓荒者角色的google應該也早就預見了這樣的結局匪凉。SPDY對產品網(wǎng)絡體驗的提升到底如何,恐怕只有各大廠產品經(jīng)理才清楚了徙融。

3. 救世主HTTP2.0

SPDY的誕生和表現(xiàn)說明了兩件事情:一是在現(xiàn)有互聯(lián)網(wǎng)設施基礎和http協(xié)議廣泛使用的前提下洒缀,是可以通過修改協(xié)議層來優(yōu)化http1.x的。二是針對http1.x的修改確實效果明顯而且業(yè)界反饋很好欺冀。正是這兩點讓IETF(Internet Enginerring Task Force)開始正式考慮制定HTTP2.0的計劃树绩,最后決定以SPDY/3為藍圖起草HTTP2.0,SPDY的部分設計人員也被邀請參與了HTTP2.0的設計隐轩。

3.1 HTTP2.0需要考慮的問題

HTTP2.0與SPDY的起點不同饺饭,SPDY可以說是google的“玩具”,最早出現(xiàn)在自家的chrome瀏覽器和server上职车,好不好玩以及別人會不會跟著一起玩對google來說無關痛癢瘫俊。但HTTP2.0作為業(yè)界標準還沒出生就是眾人矚目的焦點,一開始如果有什么瑕疵或者不兼容的問題影響可能又是數(shù)十年之久悴灵,所以考慮的問題和角度要非常之廣扛芽。我們來看下HTTP2.0一些重要的設計前提:

客戶端向server發(fā)送request這種基本模型不會變。

老的scheme不會變积瞒,使用http://和https://的服務和應用不會要做任何更改川尖,不會有http2://。

使用http1.x的客戶端和服務器可以無縫的通過代理方式轉接到http2.0上茫孔。

不識別http2.0的代理服務器可以將請求降級到http1.x叮喳。

因為客戶端和server之間在確立使用http1.x還是http2.0之前,必須要要確認對方是否支持http2.0缰贝,所以這里必須要有個協(xié)商的過程馍悟。最簡單的協(xié)商也要有一問一答,客戶端問server答剩晴,即使這種最簡單的方式也多了一個RTT的延遲锣咒,我們之所以要修改http1.x就是為了降低延遲,顯然這個RTT我們是無法接受的。google制定SPDY的時候也遇到了這個問題宠哄,他們的辦法是強制SPDY走https壹将,在SSL層完成這個協(xié)商過程。ssl層的協(xié)商在http協(xié)議通信之前毛嫉,所以是最適合的載體诽俯。google為此做了一個tls的拓展,叫NPN(Next Protocol Negotiation)承粤,從名字上也可以看出暴区,這個拓展主要目的就是為了協(xié)商下一個要使用的協(xié)議。HTTP2.0雖然也采用了相同的方式辛臊,不過HTTP2.0經(jīng)過激烈的討論仙粱,最終還是沒有強制HTTP2.0要走ssl層,大部分瀏覽器廠商(除了IE)卻只實現(xiàn)了基于https的2.0協(xié)議彻舰。HTTP2.0沒有使用NPN伐割,而是另一個tls的拓展叫ALPN(Application Layer Protocol Negotiation)。SPDY也打算從NPN遷移到ALPN了刃唤。

各瀏覽器(除了IE)之所以只實現(xiàn)了基于SSL的HTTP2.0隔心,另一個原因是走SSL請求的成功率會更高,被SSL封裝的request不會被監(jiān)聽和修改尚胞,這樣網(wǎng)絡中間的網(wǎng)絡設備就無法基于http1.x的認知去干涉修改request硬霍,http2.0的request如果被意外的修改,請求的成功率自然會下降笼裳。

HTTP2.0協(xié)議沒有強制使用SSL是因為聽到了很多的反對聲音唯卖,畢竟https和http相比,在不優(yōu)化的前提下性能差了不少躬柬,要把https優(yōu)化到幾乎不增加延遲的程度又需要花費不少力氣拜轨。IETF面對這種兩難的處境做了妥協(xié),但大部分瀏覽器廠商(除了IE)并不買帳允青,他們只認https2.0撩轰。對于app開發(fā)者來說,他們可以堅持使用沒有ssl的http2.0昧廷,不過要承擔一個多余的RTT延遲和請求可能被破壞的代價。

3.1 HTTP2.0主要改動

HTTP2.0作為新版協(xié)議偎箫,改動細節(jié)必然很多木柬,不過對應用開發(fā)者和服務提供商來說,影響較大的就幾點淹办。

新的二進制格式(Binary Format)

http1.x誕生的時候是明文協(xié)議眉枕,其格式由三部分組成:start line(request line或者status line),header,body速挑。要識別這3部分就要做協(xié)議解析谤牡,http1.x的解析是基于文本±驯Γ基于文本協(xié)議的格式解析存在天然缺陷翅萤,文本的表現(xiàn)形式有多樣性,要做到健壯性考慮的場景必然很多腊满,二進制則不同套么,只認0和1的組合√嫉埃基于這種考慮http2.0的協(xié)議解析決定采用二進制格式胚泌,實現(xiàn)方便且健壯。

有人可能會覺得基于文本的http調試方便很多肃弟,像firebug玷室,chrome,charles等不少工具都可以即時調試修改請求笤受。實際上現(xiàn)在很多請求都是走https了穷缤,要調試https請求必須有私鑰才行。http2.0的絕大部分request應該都是走https感论,所以調試方便無法作為一個有力的考慮因素了绅项。curl,tcpdump比肄,wireshark這些工具會更適合http2.0的調試快耿。

http2.0用binary格式定義了一個一個的frame,和http1.x的格式對比如下圖:


[圖10]

http2.0的格式定義更接近tcp層的方式芳绩,這張二機制的方式十分高效且精簡掀亥。length定義了整個frame的開始到結束,type定義frame的類型(一共10種)妥色,flags用bit位定義一些重要的參數(shù)搪花,stream id用作流控制,剩下的payload就是request的正文了嘹害。

雖然看上去協(xié)議的格式和http1.x完全不同了撮竿,實際上http2.0并沒有改變http1.x的語義,只是把原來http1.x的header和body部分用frame重新封裝了一層而已笔呀。調試的時候瀏覽器甚至會把http2.0的frame自動還原成http1.x的格式幢踏。具體的協(xié)議關系可以用下圖表示:

[圖11]

連接共享

http2.0要解決的一大難題就是多路復用(MultiPlexing),即連接共享许师。上面協(xié)議解析中提到的stream id就是用作連接共享機制的房蝉。一個request對應一個stream并分配一個id僚匆,這樣一個連接上可以有多個stream,每個stream的frame可以隨機的混雜在一起搭幻,接收方可以根據(jù)stream id將frame再歸屬到各自不同的request里面咧擂。

前面還提到過連接共享之后,需要優(yōu)先級和請求依賴的機制配合才能解決關鍵請求被阻塞的問題檀蹋。http2.0里的每個stream都可以設置又優(yōu)先級(Priority)和依賴(Dependency)松申。優(yōu)先級高的stream會被server優(yōu)先處理和返回給客戶端,stream還可以依賴其它的sub streams续扔。優(yōu)先級和依賴都是可以動態(tài)調整的攻臀。動態(tài)調整在有些場景下很有用,假想用戶在用你的app瀏覽商品的時候纱昧,快速的滑動到了商品列表的底部刨啸,但前面的請求先發(fā)出,如果不把后面的請求優(yōu)先級設高识脆,用戶當前瀏覽的圖片要到最后才能下載完成设联,顯然體驗沒有設置優(yōu)先級好。同理依賴在有些場景下也有妙用灼捂。

header壓縮

前面提到過http1.x的header由于cookie和user agent很容易膨脹离例,而且每次都要重復發(fā)送。http2.0使用encoder來減少需要傳輸?shù)膆eader大小悉稠,通訊雙方各自cache一份header fields表宫蛆,既避免了重復header的傳輸,又減小了需要傳輸?shù)拇笮〉拿汀8咝У膲嚎s算法可以很大的壓縮header耀盗,減少發(fā)送包的數(shù)量從而降低延遲。

這里普及一個小知識點∝宰穑現(xiàn)在大家都知道tcp有slow start的特性叛拷,三次握手之后開始發(fā)送tcp segment,第一次能發(fā)送的沒有被ack的segment數(shù)量是由initial tcp window大小決定的岂却。這個initial tcp window根據(jù)平臺的實現(xiàn)會有差異忿薇,但一般是2個segment或者是4k的大小(一個segment大概是1500個字節(jié))躏哩,也就是說當你發(fā)送的包大小超過這個值的時候署浩,要等前面的包被ack之后才能發(fā)送后續(xù)的包,顯然這種情況下延遲更高扫尺。intial window也并不是越大越好筋栋,太大會導致網(wǎng)絡節(jié)點的阻塞,丟包率就會增加器联,具體細節(jié)可以參考IETF這篇文章二汛。http的header現(xiàn)在膨脹到有可能會超過這個intial window的值了,所以更顯得壓縮header的重要性拨拓。

壓縮算法的選擇

SPDY/2使用的是gzip壓縮算法肴颊,但后來出現(xiàn)的兩種攻擊方式BREACHCRIME使得即使走ssl的SPDY也可以被破解內容,最后綜合考慮采用的是一種叫HPACK的壓縮算法渣磷。這兩個漏洞和相關算法可以點擊鏈接查看更多的細節(jié)婿着,不過這種漏洞主要存在于瀏覽器端,因為需要通過javascript來注入內容并觀察payload的變化醋界。

重置連接表現(xiàn)更好

很多app客戶端都有取消圖片下載的功能場景竟宋,對于http1.x來說,是通過設置tcp segment里的reset flag來通知對端關閉連接的形纺。這種方式會直接斷開連接,下次再發(fā)請求就必須重新建立連接。http2.0引入RST_STREAM類型的frame锋玲,可以在不斷開連接的前提下取消某個request的stream汤徽,表現(xiàn)更好。

Server Push

Server Push的功能前面已經(jīng)提到過脂新,http2.0能通過push的方式將客戶端需要的內容預先推送過去挪捕,所以也叫“cache push”。另外有一點值得注意的是争便,客戶端如果退出某個業(yè)務場景级零,出于流量或者其它因素需要取消server push,也可以通過發(fā)送RST_STREAM類型的frame來做到滞乙。

流量控制(Flow Control)

TCP協(xié)議通過sliding window的算法來做流量控制奏纪。發(fā)送方有個sending window,接收方有receive window酷宵。http2.0的flow control是類似receive window的做法亥贸,數(shù)據(jù)的接收方通過告知對方自己的flow window大小表明自己還能接收多少數(shù)據(jù)。只有Data類型的frame才有flow control的功能浇垦。對于flow control炕置,如果接收方在flow window為零的情況下依然更多的frame,則會返回block類型的frame男韧,這種場景一般表明http2.0的部署出了問題朴摊。

Nagle Algorithm vs TCP Delayed Ack

tcp協(xié)議優(yōu)化的一個經(jīng)典場景是:Nagle算法Berkeley的delayed ack算法的對立。http2.0并沒有對tcp層做任何修改此虑,所以這種對立導致的高延遲問題依然存在甚纲。要么通過TCP_NODELAY禁用Nagle算法,要么通過TCP_QUICKACK禁用delayed ack算法朦前。貌似http2.0官方建議是設置TCP_NODELAY介杆。

更安全的SSL

HTTP2.0使用了tls的拓展ALPN來做協(xié)議升級鹃操,除此之外加密這塊還有一個改動,HTTP2.0對tls的安全性做了近一步加強春哨,通過黑名單機制禁用了幾百種不再安全的加密算法荆隘,一些加密算法可能還在被繼續(xù)使用。如果在ssl協(xié)商過程當中赴背,客戶端和server的cipher suite沒有交集椰拒,直接就會導致協(xié)商失敗,從而請求失敗凰荚。在server端部署http2.0的時候要特別注意這一點燃观。

3.2 HTTP2.0里的負能量

SPDY和HTTP2.0之間的曖昧關系,以及google作為SPDY的創(chuàng)造者便瑟,這兩點很容易讓陰謀論者懷疑google是否會成為協(xié)議的最終收益方缆毁。這其實是廢話,google當然會受益胳徽,任何新協(xié)議使用者都會從中受益积锅,至于誰吃肉,誰喝湯看的是自己的本事养盗。從整個協(xié)議的變遷史也可以粗略看出缚陷,新協(xié)議的誕生完全是針對業(yè)界現(xiàn)存問題對癥下藥,并沒有google業(yè)務相關的痕跡存在往核,google至始至終只扮演了一個角色:you can you up箫爷。

HTTP2.0不會是萬金油,但抹了也不會有副作用聂儒。HTTP2.0最大的亮點在于多路復用虎锚,而多路復用的好處只有在http請求量大的場景下才明顯,所以有人會覺得只適用于瀏覽器瀏覽大型站點的時候衩婚。這么說其實沒錯窜护,但http2.0的好處不僅僅是multiplexing,請求壓縮非春,優(yōu)先級控制柱徙,server push等等都是亮點。對于內容型移動端app來說奇昙,比如淘寶app护侮,http請求量大,多路復用還是能產生明顯的體驗提升储耐。多路復用對延遲的改變可以參考下這個測試網(wǎng)址羊初。

HTTP2.0對于ssl的依賴使得有些開發(fā)者望而生畏。不少開發(fā)者對ssl還停留在高延遲什湘,CPU性能損耗长赞,配置麻煩的印象中晦攒。其實ssl于http結合對性能的影響已經(jīng)可以優(yōu)化到忽略的程度了,網(wǎng)上也有不少文章可以參考得哆。HTTP2.0也可以不走ssl勤家,有些場景確實可能不適合https,比如對代理服務器的cache依賴柳恐,對于內容安全性不敏感的get請求可以通過代理服務器緩存來優(yōu)化體驗。

3.3 HTTP2.0的現(xiàn)狀

HTTP2.0作為新版本的網(wǎng)絡協(xié)議肯定需要一段時間去普及热幔,但HTTP本身屬于應用層協(xié)議乐设,和當年的網(wǎng)絡層協(xié)議IPV6不同,離底層協(xié)議越遠绎巨,對網(wǎng)絡基礎硬件設施的影響就越小近尚。HTTP2.0甚至還特意的考慮了與HTTP1.x的兼容問題,只是在HTTP1.x的下面做了一層framing layer场勤,更使得其普及的阻力變小戈锻。所以不出意外,HTTP2.0的普及速度可能會遠超大部分人的預期和媳。

Firefox 2015年在其瀏覽器流量中檢測到格遭,有13%的http流量已經(jīng)使用了http2.0,27%的https也是http2.0留瞳,而且還處于持續(xù)的增長當中拒迅。一般用戶察覺不到是否使用了http2.0,不過可以裝這樣一個插件她倘,安裝之后如果網(wǎng)站是http2.0的璧微,在地址欄的最右邊會有個閃電圖標。還可以使用這個網(wǎng)站來測試硬梁。對于開發(fā)者來說前硫,可以通過Web Developer的Network來查看協(xié)議細節(jié),如下圖:

[圖12]

其中Version:HTTP/2.0已經(jīng)很明確表明協(xié)議類型荧止,F(xiàn)irefox還在header里面插入了X-Firefox-Spdy:“h2”屹电,也可以看出是否使用http2.0。

Chrome在2015年檢測到的http2.0流量大概有18%罩息。不過這個數(shù)字本來會更高嗤详,因為Chrome現(xiàn)在很大一部分流量都在試驗QUIC(google正在開辟的另一塊疆土)。Chrome上也可以使用類似的插件來判斷網(wǎng)站是否是使用http2.0瓷炮。

4. 移動端HTTP現(xiàn)狀4.1 iOS下http現(xiàn)狀

iOS系統(tǒng)是從iOS8開始才通過NSURLSession來支持SPDY的葱色,iOS9+開始自動支持http2.0。實際上apple對http2.0非常有信心娘香,推廣力度也很大苍狰。新版本ATS機制默認使用https來進行網(wǎng)絡傳輸办龄。APN(Apple Push Notifiction)在iOS9上也已經(jīng)是通過http2.0來實現(xiàn)的了。iOS9 sdk里的NSURLSession默認使用http2.0淋昭,而且對開發(fā)者來說是完全透明的俐填,甚至沒有api來知道到底是用的哪個版本的http協(xié)議。

對于開發(fā)者來說到底怎么去配置最佳的http使用方案呢翔忽?在我看來英融,因app而異,主要從兩方面來考慮:一是app本身http流量是否大而且密集歇式,二是開發(fā)團隊本身的技術條件驶悟。http2.0的部署相對容易很多,客戶端開發(fā)者甚至不用做什么改動材失,只需要使用iOS9的SDK編譯即可痕鳍,但缺點是http2.0只能適用于iOS9的設備。SPDY的部署相對麻煩一些龙巨,但優(yōu)點是可以兼顧iOS6+的設備笼呆。iOS端的SPDY可以使用twitter開發(fā)的CocoaSPDY方案,但有一點需要特別處理:

由于蘋果的TLS實現(xiàn)不支持NPN旨别,所以通過NPN協(xié)商使用SPDY就無法通過默認443端口來實現(xiàn)诗赌。有兩種做法,一是客戶端和server同時約定好使用另一個端口號來做NPN協(xié)商秸弛,二是server這邊通過request header智能判斷客戶端是否支持SPDY而越過NPN協(xié)商過程境肾。第一種方法會簡單一點,不過需要從框架層將所有的http請求都map到另一個port胆屿,url mapping可以參考我之前的一篇文章奥喻。twitter自己的網(wǎng)站twitter.com使用的是第二種方法。

瀏覽器端(比如Chrome)非迹,server端(比如nginx)都陸續(xù)打算放棄支持spdy了环鲤,畢竟google官方都宣布要停止維護了。spdy會是一個過渡方案憎兽,會隨著iOS9的普及會逐步消失冷离,所以這部分的技術投入需要開發(fā)團隊自己去衡量。

4.2 Android下http現(xiàn)狀

android和iOS情況類似纯命,http2.0只能在新系統(tǒng)下支持西剥,spdy作為過渡方案仍然有存在的必要。

對于使用webview的app來說亿汞,需要基于chrome內核的webview才能支持spdy和http2.0瞭空,而android系統(tǒng)的webview是從android4.4(KitKat)才改成基于chrome內核的。

對于使用native api調用的http請求來說,okhttp是同時支持spdy和http2.0的可行方案咆畏。如果使用ALPN南捂,okhttp要求android系統(tǒng)5.0+(實際上,android4.4上就有了ALPN的實現(xiàn)旧找,不過有bug溺健,知道5.0才正式修復),如果使用NPN钮蛛,可以從android4.0+開始支持鞭缭,不過NPN也是屬于將要被淘汰的協(xié)議。

結束語

以上是HTTP從1.x到SPDY魏颓,再到HTTP2.0的一些主要變遷技術點缚去。HTTP2.0正處于逐步應用到線上產品和服務的階段,可以預見未來會有不少新的坑產生和與之對應的優(yōu)化技巧琼开,HTTP1.x和SPDY也將在一段時間內繼續(xù)發(fā)揮余熱。作為工程師枕荞,需要了解這些協(xié)議背后的技術細節(jié)柜候,才能打造高性能的網(wǎng)絡框架,從而提升我們的產品體驗躏精。

參考鏈接:





以上筆記轉載自以下文章渣刷,有許多改動:

知乎作者victor yu的相關回答:

https://www.zhihu.com/question/34074946/answer/108588042

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矗烛,隨后出現(xiàn)的幾起案子辅柴,更是在濱河造成了極大的恐慌,老刑警劉巖瞭吃,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碌嘀,死亡現(xiàn)場離奇詭異,居然都是意外死亡歪架,警方通過查閱死者的電腦和手機股冗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來和蚪,“玉大人止状,你說我怎么就攤上這事≡芘” “怎么了怯疤?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長催束。 經(jīng)常有香客問我集峦,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任少梁,我火速辦了婚禮洛口,結果婚禮上,老公的妹妹穿的比我還像新娘凯沪。我一直安慰自己第焰,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布妨马。 她就那樣靜靜地躺著挺举,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烘跺。 梳的紋絲不亂的頭發(fā)上湘纵,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音滤淳,去河邊找鬼梧喷。 笑死,一個胖子當著我的面吹牛脖咐,可吹牛的內容都是我干的铺敌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼屁擅,長吁一口氣:“原來是場噩夢啊……” “哼偿凭!你這毒婦竟也來了?” 一聲冷哼從身側響起派歌,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤弯囊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胶果,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匾嘱,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年早抠,在試婚紗的時候發(fā)現(xiàn)自己被綠了奄毡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡贝或,死狀恐怖吼过,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情咪奖,我是刑警寧澤盗忱,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站羊赵,受9級特大地震影響趟佃,放射性物質發(fā)生泄漏扇谣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一闲昭、第九天 我趴在偏房一處隱蔽的房頂上張望罐寨。 院中可真熱鬧,春花似錦序矩、人聲如沸鸯绿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓶蝴。三九已至,卻和暖如春租幕,著一層夾襖步出監(jiān)牢的瞬間舷手,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工劲绪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留男窟,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓贾富,卻偏偏與公主長得像歉眷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祷安,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容