一個(gè)頁(yè)面從輸入 URL 敲回車(chē)(或觸摸屏確認(rèn))到頁(yè)面加載顯示完成總結(jié)

輸入U(xiǎn)RL的時(shí)候

??瀏覽器根據(jù)自己的算法,以及你是否處于隱私瀏覽模式,會(huì)在瀏覽器的地址框下方給出輸入建議。大部分算法會(huì)優(yōu)先考慮根據(jù)你的搜索歷史和書(shū)簽等內(nèi)容給出建議。
??同時(shí),瀏覽器預(yù)判斷是否是歷史請(qǐng)求的url,并計(jì)算請(qǐng)求的概率,可能為了加快請(qǐng)求速度而預(yù)先在后臺(tái)與幾項(xiàng)歷史相似記錄建立tcp連接。

敲入回車(chē)(或觸摸屏確認(rèn))

??若敲入回車(chē), 在這個(gè)時(shí)刻,一個(gè)專用于回車(chē)鍵的電流回路被直接地或者通過(guò)電容器間接地閉合了,使得少量的電流進(jìn)入了鍵盤(pán)的邏輯電路系統(tǒng)。這個(gè)系統(tǒng)會(huì)掃描每個(gè)鍵的狀態(tài),對(duì)于按鍵開(kāi)關(guān)的電位彈跳變化進(jìn)行噪音消除,并將其轉(zhuǎn)化為鍵盤(pán)碼值。在這里,回車(chē)的碼值是13。鍵盤(pán)控制器在得到碼值之后,將其編碼,將信號(hào)傳給cpu。【原理是利用金屬把兩個(gè)觸點(diǎn)接通或斷開(kāi)以輸入信號(hào),或者利用霍爾效應(yīng)開(kāi)關(guān)(利用磁場(chǎng)變化)和電容開(kāi)關(guān)(利用電流和電壓變化)產(chǎn)生輸入信號(hào)】(注: 當(dāng)一塊通有電流的金屬或半導(dǎo)體薄片垂直地放在磁場(chǎng)中時(shí),薄片的兩端就會(huì)產(chǎn)生電位差,這種現(xiàn)象就稱為霍爾效應(yīng)。)
??若觸摸屏確認(rèn), 在現(xiàn)代電容屏上,當(dāng)用戶把手指放在屏幕上時(shí),一小部分電流從傳導(dǎo)層的靜電域經(jīng)過(guò)手指?jìng)鲗?dǎo),形成了一個(gè)回路,使得屏幕上觸控的那一點(diǎn)電壓下降,屏幕控制器產(chǎn)生一個(gè)中斷,報(bào)告這次“點(diǎn)擊”的坐標(biāo),然后移動(dòng)操作系統(tǒng)通知當(dāng)前活躍的應(yīng)用,有一個(gè)點(diǎn)擊事件發(fā)生在它的某個(gè)GUI部件上了,現(xiàn)在這個(gè)部件是虛擬鍵盤(pán)的按鈕,虛擬鍵盤(pán)引發(fā)一個(gè)軟中斷,返回給OS一個(gè)“按鍵按下”消息, 這個(gè)消息又返回來(lái)向當(dāng)前活躍的應(yīng)用通知一個(gè)“按鍵按下”事件。

從內(nèi)存到CPU

??通過(guò)電壓高低的變化接收到信號(hào),電流流經(jīng)晶體管的半導(dǎo)體、這些晶體管構(gòu)成集成電路, 通過(guò)電壓就能控制線路開(kāi)閉, 實(shí)現(xiàn)「與」「或」「非」等邏輯電路門(mén),對(duì)信息計(jì)算處理,同時(shí)由寄存器存儲(chǔ)單元來(lái)加載和存儲(chǔ)數(shù)據(jù)。簡(jiǎn)單點(diǎn)說(shuō), 數(shù)據(jù)從輸入設(shè)備流經(jīng)內(nèi)存,等待CPU的處理,這些將要處理的信息是按字節(jié)存儲(chǔ)的,也就是以8位二進(jìn)制數(shù)或8比特為1個(gè)單元存儲(chǔ)。(這些信息可以是數(shù)據(jù)或指令。數(shù)據(jù)可以是二進(jìn)制表示的字符、數(shù)字或顏色等等。而指令告訴CPU對(duì)數(shù)據(jù)執(zhí)行哪些操作,比如完成加法、減法或移位運(yùn)算)

從 CPU 到操作系統(tǒng)內(nèi)核

??CPU接收到信號(hào)后會(huì)觸發(fā) CPU 的中斷機(jī)制(中斷Interrupt是指處理器接收到來(lái)自硬體或軟體的信號(hào),提示發(fā)生了某些事件,應(yīng)該被注意,這種情況就稱為中斷),當(dāng)中斷發(fā)生時(shí),CPU 會(huì)停下當(dāng)前運(yùn)行的程序,保存當(dāng)前執(zhí)行狀態(tài)(如 PC 值( PC是一個(gè)16位的計(jì)數(shù)器。用于存放和指示下一條要執(zhí)行的指令的地址)),進(jìn)入 IRQ 狀態(tài)(中斷處理線狀態(tài)),然后跳轉(zhuǎn)到對(duì)應(yīng)的中斷處理程序執(zhí)行,這個(gè)程序由內(nèi)核驅(qū)動(dòng)來(lái)實(shí)現(xiàn)。

從操作系統(tǒng)到瀏覽器

??由操作系統(tǒng)內(nèi)核驅(qū)動(dòng)完成對(duì)硬件信號(hào)的抽象(Mac OS X把信號(hào)翻譯成鍵碼值,Windows 把鍵盤(pán)按下的事件傳送給驅(qū)動(dòng),把HID的信號(hào)轉(zhuǎn)換成一個(gè)掃描碼),然后將事件分發(fā)給合適的(活躍的,或者正在監(jiān)聽(tīng)的)應(yīng)用程序(如瀏覽器或APP)。

瀏覽器解析URL

??瀏覽器解析URL獲取協(xié)議,主機(jī),端口,路徑。解析過(guò)程沒(méi)有協(xié)議的默認(rèn)加上HTTP協(xié)議,沒(méi)有端口的默認(rèn)為對(duì)應(yīng)協(xié)議默認(rèn)端口,(如HTTP的80端口,HTTPS的443端口,F(xiàn)TP的21端口,SSH的22端口等等),并且對(duì)URL檢查輸入是否含有不是 a-z, A-Z,0-9, - 或者 . 的字符,有的話進(jìn)行unicode編碼。檢查主機(jī)是域名還是IP地址,若是IP,跳過(guò)DNS查詢(域名解析)。

檢查 HSTS 列表

??瀏覽器檢查自帶的“預(yù)加載 HSTS(HTTP嚴(yán)格傳輸安全)”列表,這個(gè)列表里包含了那些請(qǐng)求瀏覽器只使用HTTPS進(jìn)行連接的網(wǎng)站。
??如果網(wǎng)站在這個(gè)列表里,瀏覽器會(huì)使用 HTTPS 而不是 HTTP 協(xié)議,否則,最初的請(qǐng)求會(huì)使用HTTP協(xié)議發(fā)送。
??注意,一個(gè)網(wǎng)站哪怕不在 HSTS 列表里,也可以要求瀏覽器對(duì)自己使用 HSTS 政策進(jìn)行訪問(wèn)。瀏覽器向網(wǎng)站發(fā)出第一個(gè) HTTP 請(qǐng)求之后,網(wǎng)站會(huì)返回瀏覽器一個(gè)響應(yīng),請(qǐng)求瀏覽器只使用 HTTPS 發(fā)送請(qǐng)求。然而,就是這第一個(gè) HTTP 請(qǐng)求,卻可能會(huì)使用戶受到 downgrade attack 的威脅,這也是為什么現(xiàn)代瀏覽器都預(yù)置了 HSTS 列表。

DNS 查詢

??瀏覽器檢查域名是否在緩存當(dāng)中(要查看 Chrome 當(dāng)中的緩存, 打開(kāi) chrome://net-internals/#dns)。
??如果緩存中沒(méi)有,就去調(diào)用 gethostbyname 庫(kù)函數(shù)(操作系統(tǒng)不同函數(shù)也不同)進(jìn)行查詢。
??gethostbyname 函數(shù)在試圖進(jìn)行DNS解析之前首先檢查域名是否在本地 Hosts 里,Hosts 的位置 不同的操作系統(tǒng)有所不同
??如果 gethostbyname 沒(méi)有這個(gè)域名的緩存記錄,也沒(méi)有在 hosts 里找到,它將會(huì)向 DNS 服務(wù)器發(fā)送一條 DNS 查詢請(qǐng)求。DNS 服務(wù)器是由網(wǎng)絡(luò)通信棧提供的,通常是本地路由器或者 ISP(互聯(lián)網(wǎng)服務(wù)提供商) 的緩存 DNS 服務(wù)器。
??查詢本地 DNS 服務(wù)器。
??如果 DNS 服務(wù)器和我們的主機(jī)在同一個(gè)子網(wǎng)內(nèi),系統(tǒng)會(huì)按照下面的 ARP 過(guò)程對(duì) DNS 服務(wù)器進(jìn)行 ARP查詢。
??如果 DNS 服務(wù)器和我們的主機(jī)在不同的子網(wǎng),系統(tǒng)會(huì)按照下面的 ARP 過(guò)程對(duì)默認(rèn)網(wǎng)關(guān)進(jìn)行查詢。

ARP 過(guò)程

??要想發(fā)送 ARP(地址解析協(xié)議)廣播,我們需要有一個(gè)目標(biāo) IP 地址,同時(shí)還需要知道用于發(fā)送 ARP 廣播的接口的 MAC 地址。
??首先查詢 ARP 緩存,如果緩存命中,我們返回結(jié)果:目標(biāo) IP(邏輯地址) = MAC(物理地址)
??如果緩存沒(méi)有命中:
??查看路由表,看看目標(biāo) IP 地址是不是在本地路由表中的某個(gè)子網(wǎng)內(nèi)。是的話,使用跟那個(gè)子網(wǎng)相連的接口,否則使用與默認(rèn)網(wǎng)關(guān)相連的接口。
??查詢選擇的網(wǎng)絡(luò)接口的 MAC 地址
??我們發(fā)送一個(gè)二層( OSI 模型 中的數(shù)據(jù)鏈路層)ARP 請(qǐng)求:
??ARP Request:

Sender MAC: interface:mac:address:here
Sender IP: interface.ip.goes.here
Target MAC: FF:FF:FF:FF:FF:FF (Broadcast)
Target IP: target.ip.goes.here

??根據(jù)連接主機(jī)和路由器的硬件類(lèi)型不同,可以分為以下幾種情況:
??直連:
????如果我們和路由器是直接連接的,路由器會(huì)返回一個(gè) ARP Reply (見(jiàn)下面)。
??集線器:
????如果我們連接到一個(gè)集線器,集線器會(huì)把 ARP 請(qǐng)求向所有其它端口廣播,如果路由器也“連接”在其中,它會(huì)返回一個(gè) ARP Reply 。
??交換機(jī):
????如果我們連接到了一個(gè)交換機(jī),交換機(jī)會(huì)檢查本地 CAM/MAC 表,看看哪個(gè)端口有我們要找的那個(gè) MAC 地址,如果沒(méi)有找到,交換機(jī)會(huì)向所有其它端口廣播這個(gè) ARP 請(qǐng)求。
??如果交換機(jī)的 MAC/CAM 表中有對(duì)應(yīng)的條目,交換機(jī)會(huì)向有我們想要查詢的 MAC 地址的那個(gè)端口發(fā)送 ARP 請(qǐng)求。
??如果路由器也“連接”在其中,它會(huì)返回一個(gè) ARP Reply
??ARP Reply:

Sender MAC: target:mac:address:here
Sender IP: target.ip.goes.here
Target MAC: interface:mac:address:here
Target IP: interface.ip.goes.here

??現(xiàn)在我們有了 DNS 服務(wù)器或者默認(rèn)網(wǎng)關(guān)的 IP 地址,我們可以繼續(xù) DNS 請(qǐng)求了:
??使用 53 端口向 DNS 服務(wù)器發(fā)送 UDP 請(qǐng)求包,如果響應(yīng)包太大,會(huì)使用 TCP 協(xié)議
??如果本地/ISP(互聯(lián)網(wǎng)服務(wù)提供商) DNS 服務(wù)器沒(méi)有找到結(jié)果,它會(huì)發(fā)送一個(gè)遞歸查詢請(qǐng)求,一層一層向高層 DNS 服務(wù)器做查詢,直到查詢到起始授權(quán)機(jī)構(gòu),如果找到會(huì)把結(jié)果返回。
??即會(huì)先從 root nameservers 找起。 即是假如你要查詢 www.example.com ,會(huì)先從包含根結(jié)點(diǎn)的 13 臺(tái)最高級(jí)域名服務(wù)器開(kāi)始。
??接著,以從右向左的方式遞進(jìn),找到 com. 然后向包含 com 的 TLD(頂級(jí)域名) nameservers 發(fā)送 DNS 請(qǐng)求。接著找到包含 example 的 DNS server。
??現(xiàn)在進(jìn)入到了example.com 部分,即是現(xiàn)在正在詢問(wèn)的是權(quán)威服務(wù)器,該服務(wù)器里面包含了你想要的域名信息,也就是拿到了最后的結(jié)果 record 。
??遞歸查詢的 DNS Server 接受到這 record 之后, 會(huì)將該record 保存一份到本地。 如果下一次你再請(qǐng)求這個(gè) domain 時(shí),我就可以直接返回給你了。由于每條記錄都會(huì)存在 TLL ,所以 server 每隔一段時(shí)間都會(huì)發(fā)送一次請(qǐng)求,獲取新的 record,
??最后,再經(jīng)由最近的 DNS Server 將該條 record 返回。 同樣,你的設(shè)備也會(huì)存一份該 record 的副本。 之后,就是 TCP 的事了。

??注:DNS 解析其實(shí)是一個(gè)很復(fù)雜的過(guò)程,在 PC 上,我們采用域名發(fā)散策略( 目的是充分利用現(xiàn)代瀏覽器的多線程并發(fā)下載能力。由于瀏覽器的限制,每個(gè)瀏覽器,允許對(duì)每個(gè)域名的連接數(shù)一般是有上限的),是因?yàn)樵?PC 端上,DNS 解析通常而言只需要幾十 ms ,可以接受。而移動(dòng)端,2G 網(wǎng)絡(luò),3G網(wǎng)絡(luò),4G網(wǎng)絡(luò)/wifi 強(qiáng)網(wǎng),而且移動(dòng) 4G 容易在信號(hào)不理想的地段降級(jí)成 2G ,通過(guò)大量的數(shù)據(jù)采集和真實(shí)網(wǎng)絡(luò)抓包分析(存在DNS解析的請(qǐng)求),DNS的消耗相當(dāng)可觀,2G網(wǎng)絡(luò)大量5-10s,3G網(wǎng)絡(luò)平均也要3-5s(數(shù)據(jù)來(lái)源于淘寶)。
??因?yàn)樵谠黾佑虻耐瑫r(shí),往往會(huì)給瀏覽器帶來(lái) DNS 解析的開(kāi)銷(xiāo)。所以在這種情況下,提出了域名收斂,減少域名數(shù)量可以降低 DNS 解析的成本。

建立tcp連接

??好,經(jīng)過(guò)dns查詢我們已經(jīng)得到了目標(biāo)ip,加上端口號(hào), 調(diào)用系統(tǒng)庫(kù)函數(shù) socket,打開(kāi)一個(gè)socket與目標(biāo)IP地址的該端口建立TCP鏈接。

TCP 封包

??這個(gè)請(qǐng)求首先被交給傳輸層,在傳輸層請(qǐng)求被封裝成 TCP segment。目標(biāo)端口會(huì)被加入頭部,源端口會(huì)在系統(tǒng)內(nèi)核的動(dòng)態(tài)端口范圍內(nèi)選取(Linux下是ip_local_port_range)
??TCP segment 被送往網(wǎng)絡(luò)層,網(wǎng)絡(luò)層會(huì)在其中再加入一個(gè) IP 頭部,里面包含了目標(biāo)服務(wù)器的IP地址以及本機(jī)的IP地址,把它封裝成一個(gè)TCP packet。
??這個(gè) TCP packet 接下來(lái)會(huì)進(jìn)入鏈路層,鏈路層會(huì)在封包中加入 frame頭 部,里面包含了本地內(nèi)置網(wǎng)卡的MAC地址以及網(wǎng)關(guān)(本地路由器)的 MAC 地址。像前面說(shuō)的一樣,如果內(nèi)核不知道網(wǎng)關(guān)的 MAC 地址,它必須進(jìn)行 ARP 廣播來(lái)查詢其地址。

傳輸

??有幾種傳輸方式
??1、以太網(wǎng)
??2、WiFi
??3、蜂窩數(shù)據(jù)網(wǎng)絡(luò)
??對(duì)于大部分家庭網(wǎng)絡(luò)和小型企業(yè)網(wǎng)絡(luò)來(lái)說(shuō),封包會(huì)從本地計(jì)算機(jī)出發(fā),經(jīng)過(guò)本地網(wǎng)絡(luò),再通過(guò)調(diào)制解調(diào)器把數(shù)字信號(hào)轉(zhuǎn)換成模擬信號(hào),使其適于在電話線路,有線電視光纜和無(wú)線電話線路上傳輸。在傳輸線路的另一端,是另外一個(gè)調(diào)制解調(diào)器,它把模擬信號(hào)轉(zhuǎn)換回?cái)?shù)字信號(hào),交由下一個(gè) 網(wǎng)絡(luò)節(jié)點(diǎn) 處理。節(jié)點(diǎn)的目標(biāo)地址和源地址將在后面討論。
??大型企業(yè)和比較新的住宅通常使用光纖或直接以太網(wǎng)連接,這種情況下信號(hào)一直是數(shù)字的,會(huì)被直接傳到下一個(gè) 網(wǎng)絡(luò)節(jié)點(diǎn) 進(jìn)行處理。
??最終封包會(huì)到達(dá)管理本地子網(wǎng)的路由器。在那里出發(fā),它會(huì)繼續(xù)經(jīng)過(guò)自治區(qū)域(autonomous system, 縮寫(xiě) AS)的邊界路由器,其他自治區(qū)域,最終到達(dá)目標(biāo)服務(wù)器。一路上經(jīng)過(guò)的這些路由器會(huì)從IP數(shù)據(jù)報(bào)頭部里提取出目標(biāo)地址,并將封包正確地路由到下一個(gè)目的地。IP數(shù)據(jù)報(bào)頭部 time to live (TTL) 域的值每經(jīng)過(guò)一個(gè)路由器就減1,如果封包的TTL變?yōu)?,或者路由器由于網(wǎng)絡(luò)擁堵等原因封包隊(duì)列滿了,那么這個(gè)包會(huì)被路由器丟棄。

??上面的發(fā)送和接受過(guò)程在 TCP 連接期間會(huì)發(fā)生很多次:

??客戶端選擇一個(gè)初始序列號(hào)(ISN),將設(shè)置了 SYN 位的封包發(fā)送給服務(wù)器端,表明自己要建立連接并設(shè)置了初始序列號(hào)。

  • 服務(wù)器端接收到 SYN 包,如果它可以建立連接:

    • 服務(wù)器端選擇它自己的初始序列號(hào)
    • 服務(wù)器端設(shè)置 SYN 位,表明自己選擇了一個(gè)初始序列號(hào)
    • 服務(wù)器端把 (客戶端ISN + 1) 復(fù)制到 ACK 域,并且設(shè)置 ACK 位,表明自己接收到了客戶端的第一個(gè)封包
  • 客戶端通過(guò)發(fā)送下面一個(gè)封包來(lái)確認(rèn)這次連接:

    • 自己的序列號(hào)+1
    • 接收端 ACK+1
    • 設(shè)置 ACK 位
  • 數(shù)據(jù)通過(guò)下面的方式傳輸:

    • 當(dāng)一方發(fā)送了N個(gè) Bytes 的數(shù)據(jù)之后,將自己的 SEQ 序列號(hào)也增加N
    • 另一方確認(rèn)接收到這個(gè)數(shù)據(jù)包(或者一系列數(shù)據(jù)包)之后,它發(fā)送一個(gè) ACK 包,ACK 的值設(shè)置為接收到的數(shù)據(jù)包的最后一個(gè)序列號(hào)
  • 關(guān)閉連接時(shí):

    • 要關(guān)閉連接的一方發(fā)送一個(gè) FIN 包
    • 另一方確認(rèn)這個(gè) FIN 包,
      -并且發(fā)送自己的 FIN 包
    • 要關(guān)閉的一方使用 ACK 包來(lái)確認(rèn)接收到了 FIN

??注:通俗點(diǎn)理解tcp:

??三次握手(為什么是三次,主要是如果是兩次握手建立連接,由于網(wǎng)絡(luò)堵塞或其它原因?qū)е抡?qǐng)求端請(qǐng)求來(lái)遲,而接收端開(kāi)辟等待信息接口后沒(méi)有后續(xù)信息到來(lái)(可能已失效),影響性能和內(nèi)存損耗,所以要三次握手來(lái)確認(rèn)雙方都是在活躍狀態(tài)的)
??第一次:喂,聽(tīng)得到嗎
??第二次:聽(tīng)得到 ,確定要連接嗎
??第三次:確定,巴拉巴拉..

??四次揮手
??第一次:我不給你數(shù)據(jù)了啊
??第二次:好的收到,還有一些數(shù)據(jù)沒(méi)發(fā)完,完了我告訴你
??第三次:數(shù)據(jù)發(fā)完了,我匿了
??第四次:真的嗎,等幾秒沒(méi)回復(fù),好的我也匿了

??注:為什么HTTP協(xié)議要基于TCP來(lái)實(shí)現(xiàn)?TCP是一個(gè)端到端的可靠的面向連接的協(xié)議,所以HTTP基于傳輸層TCP協(xié)議不用擔(dān)心數(shù)據(jù)的傳輸?shù)母鞣N問(wèn)題。

TLS 握手

??客戶端發(fā)送一個(gè) ClientHello 消息到服務(wù)器端,消息中同時(shí)包含了它的 Transport Layer Security (TLS) 版本,可用的加密算法和壓縮算法。
??服務(wù)器端向客戶端返回一個(gè) ServerHello 消息,消息中包含了服務(wù)器端的TLS版本,服務(wù)器所選擇的加密和壓縮算法,以及數(shù)字證書(shū)認(rèn)證機(jī)構(gòu)(Certificate Authority,縮寫(xiě) CA)簽發(fā)的服務(wù)器公開(kāi)證書(shū),證書(shū)中包含了公鑰。客戶端會(huì)使用這個(gè)公鑰加密接下來(lái)的握手過(guò)程,直到協(xié)商生成一個(gè)新的對(duì)稱密鑰
??客戶端根據(jù)自己的信任CA列表,驗(yàn)證服務(wù)器端的證書(shū)是否可信。如果認(rèn)為可信,客戶端會(huì)生成一串偽隨機(jī)數(shù),使用服務(wù)器的公鑰加密它。這串隨機(jī)數(shù)會(huì)被用于生成新的對(duì)稱密鑰
??服務(wù)器端使用自己的私鑰解密上面提到的隨機(jī)數(shù),然后使用這串隨機(jī)數(shù)生成自己的對(duì)稱主密鑰
??客戶端發(fā)送一個(gè) Finished 消息給服務(wù)器端,使用對(duì)稱密鑰加密這次通訊的一個(gè)散列值
??服務(wù)器端生成自己的 hash 值,然后解密客戶端發(fā)送來(lái)的信息,檢查這兩個(gè)值是否對(duì)應(yīng)。如果對(duì)應(yīng),就向客戶端發(fā)送一個(gè)Finished 消息,也使用協(xié)商好的對(duì)稱密鑰加密
??從現(xiàn)在開(kāi)始,接下來(lái)整個(gè) TLS 會(huì)話都使用對(duì)稱秘鑰進(jìn)行加密,傳輸應(yīng)用層(HTTP)內(nèi)容

瀏覽器查看緩存

??url解析后, 瀏覽器會(huì)查看緩存,
??如果資源未緩存,發(fā)起新請(qǐng)求
??如果請(qǐng)求資源在緩存中, 不同的瀏覽器,不同的用戶操作,不同緩存策略,會(huì)有對(duì)緩存不同的處理(詳見(jiàn)這里)。總的來(lái)說(shuō),要么直接在緩存中取數(shù)據(jù),要么發(fā)起請(qǐng)求檢驗(yàn)緩存是否有效,返回304就是未修改,返回200就需要對(duì)緩存更新。

緩存策略通常有幾種方式
  • HTTP1.0提供Expires, Expires 頭部字段提供一個(gè)日期和時(shí)間,響應(yīng)在該日期和時(shí)間后被認(rèn)為失效。失效的緩存條目通常不會(huì)被緩存。格式一般為 "Expires: Sun, 08 Nov 2009 03:37:26 GMT"
  • HTTP1.1增加了Cache-Control: max-age=,值為以秒為單位, 而如果指定了max-age值,那么在此值內(nèi)的時(shí)間里就不會(huì)重新訪問(wèn)服務(wù)器,例如:Cache-control: max-age=5 表示當(dāng)訪問(wèn)此網(wǎng)頁(yè)后的5秒內(nèi)再次訪問(wèn)不會(huì)去服務(wù)器. (注意:cache-control max-age 和 s-maxage 將覆蓋 Expires 頭部。)
  • Last-Modified
    ??在瀏覽器第一次請(qǐng)求某一個(gè)URL時(shí),服務(wù)器端的返回狀態(tài)會(huì)是200,內(nèi)容是你請(qǐng)求的資源,同時(shí)有一個(gè)Last-Modified的屬性標(biāo)記(HttpReponse Header)此文件在服務(wù)期端最后被修改的時(shí)間,格式類(lèi)似這樣:
    ??Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT
    ??客戶端第二次請(qǐng)求此URL時(shí),根據(jù)HTTP協(xié)議的規(guī)定,瀏覽器會(huì)向服務(wù)器傳送If-Modified-Since報(bào)頭(HttpRequest Header),詢問(wèn)該時(shí)間之后文件是否有被修改過(guò):
    ??If-Modified-Since:Tue, 24 Feb 2009 08:01:04 GMT
  • ETag
    ??ETag 響應(yīng)頭部字段值是一個(gè)實(shí)體標(biāo)記,它提供一個(gè) “不透明” 的緩存驗(yàn)證器。這可能在以下幾種情況下提供更可靠的驗(yàn)證:不方便存儲(chǔ)修改日期;HTTP 日期值的 one-second 解決方案不夠用;或者原始服務(wù)器希望避免由于使用修改日期而導(dǎo)致的某些沖突。
    ??在典型用法中,當(dāng)一個(gè)URL被請(qǐng)求,Web服務(wù)器會(huì)返回資源和其相應(yīng)的ETag值,它會(huì)被放置在HTTP的“ETag”字段中:
    ??ETag: "686897696a7c876b7e"
    ??然后,客戶端可以決定是否緩存這個(gè)資源和它的ETag。以后,如果客戶端想再次請(qǐng)求相同的URL,將會(huì)發(fā)送一個(gè)包含已保存的ETag和“If-None-Match”字段的請(qǐng)求。
    ??If-None-Match: "686897696a7c876b7e"
    ??客戶端請(qǐng)求之后,服務(wù)器可能會(huì)比較客戶端的ETag和當(dāng)前版本資源的ETag。如果ETag值匹配,這就意味著資源沒(méi)有改變,服務(wù)器便會(huì)發(fā)送回一個(gè)極短的響應(yīng),包含HTTP “304 未修改”的狀態(tài)。304狀態(tài)告訴客戶端,它的緩存版本是最新的,并應(yīng)該使用它。
    ??然而,如果ETag的值不匹配,這就意味著資源很可能發(fā)生了變化,那么,一個(gè)完整的響應(yīng)就會(huì)被返回,包括資源的內(nèi)容,就好像ETag沒(méi)有被使用。這種情況下,客戶端可以用新返回的資源和新的ETag替代先前的緩存版本。

HTTP請(qǐng)求

??瀏覽器組裝http get 請(qǐng)求報(bào)文,通過(guò)tcp通道發(fā)送給目標(biāo)服務(wù)器。
??HTTP頭字段列表

負(fù)載均衡

????請(qǐng)求在進(jìn)入到真正的應(yīng)用服務(wù)器前,可能還會(huì)先經(jīng)過(guò)負(fù)責(zé)負(fù)載均衡的機(jī)器,它的作用是將請(qǐng)求合理地分配到多個(gè)服務(wù)器上,同時(shí)具備具備防攻擊等功能。
????負(fù)載均衡具體實(shí)現(xiàn)有很多種,有直接基于硬件的 F5,有操作系統(tǒng)傳輸層(TCP)上的 LVS,也有在應(yīng)用層(HTTP)實(shí)現(xiàn)的反向代理(也叫七層代理),接下來(lái)將介紹 LVS 及反向代理。

??負(fù)載均衡的策略也有很多,如果后面的多個(gè)服務(wù)器性能均衡,最簡(jiǎn)單的方法就是挨個(gè)循環(huán)一遍(Round-Robin),其它策略就不一一介紹了,可以參考 LVS 中的算法。

  • LVS

??LVS 的作用是從對(duì)外看來(lái)只有一個(gè) IP,而實(shí)際上這個(gè) IP 后面對(duì)應(yīng)是多臺(tái)機(jī)器,因此也被成為 Virtual IP。
??前面提到的 NAT 也是一種 LVS 中的工作模式,除此之外還有 DR 和 TUNNEL,具體細(xì)節(jié)這里就不展開(kāi)了,它們的缺點(diǎn)是無(wú)法跨網(wǎng)段,所以百度自己開(kāi)發(fā)了 BVS 系統(tǒng)。

  • 反向代理

??反向代理是工作在 HTTP 上的,具體實(shí)現(xiàn)可以基于 HAProxy 或 Nginx,因?yàn)榉聪虼砟芾斫?HTTP 協(xié)議,所以能做非常多的事情,比如:
??進(jìn)行很多統(tǒng)一處理,比如防攻擊策略、防抓取、SSL、gzip、自動(dòng)性能優(yōu)化等
??應(yīng)用層的分流策略都能在這里做,比如對(duì) /xx 路徑的請(qǐng)求分到 a 服務(wù)器,對(duì) /yy 路徑的請(qǐng)求分到 b 服務(wù)器,或者按照 cookie 進(jìn)行小流量測(cè)試等
??緩存,并在后端服務(wù)掛掉的時(shí)候顯示友好的 404 頁(yè)面
??監(jiān)控后端服務(wù)是否異常

HTTP 服務(wù)器請(qǐng)求處理

??數(shù)據(jù)已經(jīng)到達(dá)服務(wù)器網(wǎng)卡之后,接著網(wǎng)卡會(huì)將數(shù)據(jù)拷貝到內(nèi)存中(DMA 直接內(nèi)存存取 它允許不同速度的硬件裝置來(lái)溝通,而不需要依賴于CPU 的大量中斷負(fù)載。 否則,CPU 需要從來(lái)源把每一片段的資料復(fù)制到暫存器,然后把它們?cè)俅螌?xiě)回到新的地方。在這個(gè)時(shí)間中,CPU 對(duì)于其他的工作來(lái)說(shuō)就無(wú)法使用。),然后通過(guò)中斷來(lái)通知 CPU。cpu通過(guò)時(shí)鐘機(jī)制對(duì)指令進(jìn)行處理。同樣經(jīng)由操作系統(tǒng)內(nèi)核驅(qū)動(dòng)對(duì)硬件信息進(jìn)行抽象,把信息傳遞給對(duì)應(yīng)的處理程序。服務(wù)端的的服務(wù)器(apache,nginx,iis, Tomcat,nodejs等)通過(guò)監(jiān)聽(tīng)端口,來(lái)接收并處理請(qǐng)求信息。

??服務(wù)器把請(qǐng)求拆分為以下幾個(gè)參數(shù):
??- HTTP 請(qǐng)求方法(GET, POST, HEAD, PUT, DELETE, CONNECT, OPTIONS, 或者 TRACE)。直接在地址欄中輸入 URL 這種情況下,使用的是 GET 方法
??- 域名 如example.com
??- 請(qǐng)求路徑/頁(yè)面
??服務(wù)器驗(yàn)證 example .com 接受 GET 方法
??服務(wù)器驗(yàn)證該用戶可以使用 GET 方法(根據(jù) IP 地址,身份信息等)
??如果服務(wù)器安裝了 URL 重寫(xiě)模塊(例如 Apache 的 mod_rewrite 和 IIS 的 URL Rewrite),服務(wù)器會(huì)嘗試匹配重寫(xiě)規(guī)則,如果匹配上的話,服務(wù)器會(huì)按照規(guī)則重寫(xiě)這個(gè)請(qǐng)求
??服務(wù)器根據(jù)請(qǐng)求信息獲取相應(yīng)的響應(yīng)內(nèi)容,這種情況下由于訪問(wèn)路徑是 "/" ,會(huì)訪問(wèn)首頁(yè)文件(你可以重寫(xiě)這個(gè)規(guī)則,但是這個(gè)是最常用的)。
??服務(wù)器會(huì)使用指定的處理程序分析處理這個(gè)文件,假如使用 PHP,服務(wù)器會(huì)使用 php-fpm(請(qǐng)求處理進(jìn)程池) 解析 index 文件,并捕獲輸出,把 PHP 的輸出結(jié)果返回給請(qǐng)求者

服務(wù)端程序處理

??根據(jù)路徑和查詢參數(shù)進(jìn)行相應(yīng)處理,比如服務(wù)端處理程序選用laravel,那么抵達(dá) public/index.php 入口文件之后,laravel會(huì)定義項(xiàng)目路徑,加載框架核心文件,注冊(cè)自動(dòng)加載,錯(cuò)誤和異常處理,日志記錄機(jī)制,初始化應(yīng)用,解析url,跳轉(zhuǎn)路由,權(quán)限檢測(cè),分發(fā)請(qǐng)求,處理請(qǐng)求(數(shù)據(jù)庫(kù)查詢,數(shù)據(jù)過(guò)濾,請(qǐng)求其它服務(wù)器數(shù)據(jù)等操作 ),然后返回給瀏覽器對(duì)應(yīng)的數(shù)據(jù)包(包括http協(xié)議組成的代碼。里面包含頁(yè)面的布局、文字。數(shù)據(jù)也可能是圖片、腳本程序,反應(yīng)頭,反應(yīng)數(shù)據(jù),請(qǐng)求頭等),如果開(kāi)啟了gzip之類(lèi)的功能服務(wù)器會(huì)先把響應(yīng)內(nèi)容通過(guò)特定編碼壓縮后在返回給瀏覽器。

返回結(jié)果到瀏覽器

??瀏覽器根據(jù)響應(yīng)狀態(tài)碼判斷請(qǐng)求的狀態(tài)。
??如常見(jiàn)的:

  • 200(OK)
    ??請(qǐng)求已成功,請(qǐng)求所希望的響應(yīng)頭或數(shù)據(jù)體將隨此響應(yīng)返回。

  • 301(Moved Permanently)
    ??被請(qǐng)求的資源已永久移動(dòng)到新位置,并且將來(lái)任何對(duì)此資源的引用都應(yīng)該使用本響應(yīng)返回的若干個(gè)URI之一。如果該請(qǐng)求不是GET/HEAD, 瀏覽器通常會(huì)要求用戶確認(rèn)重定向。
    301通常用于網(wǎng)站遷移時(shí),服務(wù)器對(duì)舊的URL進(jìn)行301重定向到新的URL。這樣搜索引擎可以正確地更新原有的頁(yè)面排名等信息。

  • 302(Found)
    ??請(qǐng)求的資源現(xiàn)在臨時(shí)從不同的URI響應(yīng)請(qǐng)求。除非指定了Cache-Control或Expires,否則該響應(yīng)不可緩存。 如果當(dāng)前請(qǐng)求非HEAD或GET,瀏覽器需取得用戶確認(rèn),再進(jìn)行重定向。

  • 304(Not Modified)
    ??如果客戶端發(fā)送了一個(gè)帶條件的GET請(qǐng)求且該請(qǐng)求已被允許,而文檔的內(nèi)容(自上次訪問(wèn)以來(lái)或者根據(jù)請(qǐng)求的條件)并沒(méi)有改變。 304響應(yīng)禁止包含消息體。

  • 307(Temporary Redirect)

  • 400(Bad Request)
    ??由于包含語(yǔ)法錯(cuò)誤,當(dāng)前請(qǐng)求無(wú)法被服務(wù)器理解。400通常在服務(wù)器端表單驗(yàn)證失敗時(shí)返回。

  • 403(Forbidden)
    ??服務(wù)器已經(jīng)理解請(qǐng)求,但是拒絕執(zhí)行它。與401響應(yīng)不同的是,身份驗(yàn)證并不能提供任何幫助。

  • 404(Not Found)

  • 500(Internal Server Error)
    ??通常是代碼出錯(cuò),后臺(tái)Bug。一般的Web服務(wù)器通常會(huì)給出拋出異常的調(diào)用堆棧。 然而多數(shù)服務(wù)器即使在生產(chǎn)環(huán)境也會(huì)打出調(diào)用堆棧,這顯然是不安全的。

  • 502(Bad Gateway)
    ??作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí),從上游服務(wù)器接收到無(wú)效的響應(yīng)。
    ??如果你在用HTTP代理來(lái)翻墻,或者你配置了nginx來(lái)反向代理你的應(yīng)用,你可能會(huì)常常看到它。

  • 504(Gateway Time-out)
    ??作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí),未能及時(shí)從上游服務(wù)器收到響應(yīng)。
    注意與502的區(qū)別:502是接收到了無(wú)效響應(yīng)比如Connection Refused; 504是響應(yīng)超時(shí),通常是被墻了。
    ??然后如果緩存驗(yàn)證有效,就是使用緩存,緩存失效得到新的數(shù)據(jù)后進(jìn)行解析。如果資源可緩存,進(jìn)行緩存。

瀏覽器解析數(shù)據(jù)

??如果有 gzip 會(huì)先解壓,然后接下來(lái)最重要的問(wèn)題是要知道它的編碼是什么,比如同樣一個(gè)「中」字,在 UTF-8 編碼下它的內(nèi)容其實(shí)是「11100100 10111000 10101101」也就是「E4 B8 AD」,而在 GBK 下則是「11010110 11010000」,也就是「D6 D0」,如何才能知道文件的編碼?可以有很多判斷方法:

  • 用戶設(shè)置,在瀏覽器中可以指定頁(yè)面編碼
  • HTTP 協(xié)議中
  • <meta> 中的 charset 屬性值
  • 對(duì)于 JS 和 CSS
  • 對(duì)于 iframe

??如果在這些地方都沒(méi)指明,瀏覽器就很難處理,在它看來(lái)就是一堆「0」和「1」,比如「中文」,它在 UTF-8 下有 6 個(gè)字節(jié),如果按照 GBK 可以當(dāng)成「涓枃」這 3 個(gè)漢字來(lái)解釋,瀏覽器怎么知道到底是「中文」還是「涓枃」呢?
??不過(guò)正常人一眼就能認(rèn)出「涓枃」是錯(cuò)的,因?yàn)檫@ 3 個(gè)字太不常見(jiàn)了,所以有人就想到通過(guò)判斷常見(jiàn)字的方法來(lái)檢測(cè)編碼,典型的比如 Mozilla 的 UniversalCharsetDetection,不過(guò)這東東誤判率也很高,所以還是指明編碼的好。
??這樣后續(xù)對(duì)文本的操作就是基于「字符」(Character)的了,一個(gè)漢字就是一個(gè)字符,不用再關(guān)心它究竟是 2 個(gè)字節(jié)還是 3 個(gè)字節(jié)。

??瀏覽器對(duì)加載到的資源(HTML、JS、CSS等)進(jìn)行語(yǔ)法解析,建立相應(yīng)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如HTML的DOM)
??載入解析到的資源文件,渲染頁(yè)面,完成。

瀏覽器的渲染過(guò)程

??解析HTML文檔,構(gòu)件DOM樹(shù),下載資源,構(gòu)造CSSOM樹(shù),執(zhí)行js腳本,這些操作沒(méi)有嚴(yán)格的先后順序,以下分別解釋

  • 構(gòu)建DOM樹(shù): DOM 樹(shù)的構(gòu)建過(guò)程是一個(gè)深度遍歷過(guò)程:當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)都構(gòu)建好后才會(huì)去構(gòu)建當(dāng)前節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)。

    • Tokenizing:根據(jù)HTML規(guī)范將字符流解析為標(biāo)記
    • Lexing:詞法分析將標(biāo)記轉(zhuǎn)換為對(duì)象并定義屬性和規(guī)則
    • DOM construction:根據(jù)HTML標(biāo)記關(guān)系將對(duì)象組成DOM樹(shù)
  • 解析過(guò)程中遇到圖片、樣式表、js文件,啟動(dòng)下載

  • 構(gòu)建CSSOM樹(shù):

    • Tokenizing:字符流轉(zhuǎn)換為標(biāo)記流
    • Node:根據(jù)標(biāo)記創(chuàng)建節(jié)點(diǎn)
    • CSSOM:節(jié)點(diǎn)創(chuàng)建CSSOM樹(shù)
  • 根據(jù)DOM樹(shù)和CSSOM樹(shù)構(gòu)建渲染樹(shù)

    • 有了Render Tree,瀏覽器已經(jīng)能知道網(wǎng)頁(yè)中有哪些節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的CSS定義以及他們的從屬關(guān)系。下一步操作就是計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。從DOM樹(shù)的根節(jié)點(diǎn)遍歷所有可見(jiàn)節(jié)點(diǎn),不可見(jiàn)節(jié)點(diǎn)包括:1)script,meta這樣本身不可見(jiàn)的標(biāo)簽。2)被css隱藏的節(jié)點(diǎn),如display: none
    • 對(duì)每一個(gè)可見(jiàn)節(jié)點(diǎn),找到恰當(dāng)?shù)腃SSOM規(guī)則并應(yīng)用
    • 發(fā)布可視節(jié)點(diǎn)的內(nèi)容和計(jì)算樣式
  • js解析如下:

    • 瀏覽器創(chuàng)建Document對(duì)象并解析HTML,將解析到的元素和文本節(jié)點(diǎn)添加到文檔中,此時(shí)document.readystate為loading
    • HTML解析器遇到?jīng)]有async和defer的script時(shí),將他們添加到文檔中,然后執(zhí)行行內(nèi)或外部腳本。這些腳本會(huì)同步執(zhí)行,并且在腳本下載和執(zhí)行時(shí)解析器會(huì)暫停。這樣就可以用document.write()把文本插入到輸入流中。同步腳本經(jīng)常簡(jiǎn)單定義函數(shù)和注冊(cè)事件處理程序,他們可以遍歷和操作script和他們之前的文檔內(nèi)容
    • 當(dāng)解析器遇到設(shè)置了async屬性的script時(shí),開(kāi)始下載腳本并繼續(xù)解析文檔。腳本會(huì)在它下載完成后盡快執(zhí)行,但是解析器不會(huì)停下來(lái)等它下載。異步腳本禁止使用document.write(),它們可以訪問(wèn)自己script和之前的文檔元素
    • 當(dāng)文檔完成解析,document.readState變成interactive
    • 所有defer腳本會(huì)按照在文檔出現(xiàn)的順序執(zhí)行,延遲腳本能訪問(wèn)完整文檔樹(shù),禁止使用document.write()
    • 瀏覽器在Document對(duì)象上觸發(fā)DOMContentLoaded事件
    • 此時(shí)文檔完全解析完成,瀏覽器可能還在等待如圖片等內(nèi)容加載,等這些內(nèi)容完成載入并且所有異步腳本完成載入和執(zhí)行,document.readState變?yōu)閏omplete,window觸發(fā)load事件
  • 顯示頁(yè)面(HTML解析過(guò)程中會(huì)逐步顯示頁(yè)面)

注:
??Repaint——屏幕的一部分要重畫(huà),比如某個(gè)CSS的背景色變了。但是元素的幾何尺寸沒(méi)有變。
??Reflow——意味著元件的幾何尺寸變了,我們需要重新驗(yàn)證并計(jì)算Render Tree。是Render Tree的一部分或全部發(fā)生了變化。這就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的幾何尺寸發(fā)生了變化,需要重新布局,也就叫reflow)reflow 會(huì)從<html>這個(gè)root frame開(kāi)始遞歸往下,依次計(jì)算所有的結(jié)點(diǎn)幾何尺寸和位置,在reflow過(guò)程中,可能會(huì)增加一些frame,比如一個(gè)文本字符串必需被包裝起來(lái)。
??Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每個(gè)結(jié)點(diǎn)都會(huì)有reflow方法,一個(gè)結(jié)點(diǎn)的reflow很有可能導(dǎo)致子結(jié)點(diǎn),甚至父點(diǎn)以及同級(jí)結(jié)點(diǎn)的reflow。

參考鏈接

從輸入 URL 到頁(yè)面加載完成的過(guò)程中都發(fā)生了什么事情?
瀏覽器緩存機(jī)制
在瀏覽器地址欄輸入一個(gè)URL后回車(chē),背后會(huì)進(jìn)行哪些技術(shù)步驟?
一次完整的瀏覽器請(qǐng)求流程
當(dāng)···時(shí)發(fā)生了什么?
What happens when...
深度解析URL到頁(yè)面渲染的全過(guò)程
瀏覽器緩存詳解:expires,cache-control,last-modified,etag詳細(xì)說(shuō)明
瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘
瀏覽器的渲染原理簡(jiǎn)介
等。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

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