繼續(xù)書接上文婆廊,處理函數(shù)向orm框架索要數(shù)據(jù)帜讲,orm框架需要從db獲取數(shù)據(jù)時(shí)其弊,orm 框架負(fù)責(zé)把面向?qū)ο蟮恼埱蠓g成標(biāo)準(zhǔn)的 sql 語句癞己,然后送到后端的 db 去執(zhí)行,db 這里以 mysql 為例的話梭伐,那么一條 sql 進(jìn)來之后痹雅,db 本身也是有緩存的,不過 db 的緩存一般是用 sql 語言 hash 來存取的糊识,也就是說绩社,想要緩存能夠命中摔蓝,除了查詢的字段和方法要一樣以外,查詢的參數(shù)也要完全一模一樣才能夠使用 db 本身的查詢緩存愉耙,sql 經(jīng)過查詢緩存器贮尉,然后就會(huì)到達(dá)查詢分析器,在這里朴沿,db 會(huì)根據(jù)被搜索的數(shù)據(jù)表的索引建立情況猜谚,和 sql 語言本身的特點(diǎn),來決定使用哪一個(gè)字段的索引赌渣,值得一提的是魏铅,即使一個(gè)數(shù)據(jù)表同時(shí)在多個(gè)字段建立了索引,但是對于一條 sql 語句來說坚芜,還是只能使用一個(gè)索引览芳,所以這里就需要分析使用哪個(gè)索引效率最高了,一般來說货岭,sql 優(yōu)化在這個(gè)點(diǎn)上也是很重要的一個(gè)方面路操。
sql 由 db 返回結(jié)果集后,再由 orm 框架把結(jié)果轉(zhuǎn)換成模型對象千贯,然后由 orm 框架進(jìn)行一些邏輯處理屯仗,把準(zhǔn)備好的數(shù)據(jù),送到視圖層搔谴。在視圖層把頁面準(zhǔn)備好好后魁袜,再從動(dòng)態(tài)腳本解釋器送回到http服務(wù)器,由http服務(wù)器把這些正文加上一個(gè)響應(yīng)頭敦第,封裝成一個(gè)標(biāo)準(zhǔn)的http響應(yīng)包峰弹,再通過tcp ip協(xié)議,送回到客戶機(jī)瀏覽器芜果。
斷點(diǎn)1: HTTP響應(yīng)格式
http響應(yīng)格式與http請求格式非常類似鞠呈,也有三部分組成:狀態(tài)行,消息報(bào)頭和響應(yīng)正文右钾。
<status-line>
<headers>
<blank line>
[<response-body>]
狀態(tài)行(Response Line):
HTTP-Version Status-Code Reason-Phrase
其中蚁吝,Reason-Phrase表示狀態(tài)代碼的文本描述。狀態(tài)碼一般由三位數(shù)字組成舀射,第一個(gè)數(shù)字定義了響應(yīng)類別窘茁,含義如下:
1xx:指示信息--表示請求已接收,繼續(xù)處理脆烟。
2xx:成功--表示請求已被成功接收山林、理解、接受邢羔。
3xx:重定向--要完成請求必須進(jìn)行更進(jìn)一步的操作驼抹。
4xx:客戶端錯(cuò)誤--請求有語法錯(cuò)誤或請求無法實(shí)現(xiàn)桑孩。
5xx:服務(wù)器端錯(cuò)誤--服務(wù)器未能實(shí)現(xiàn)合法的請求。
常見狀態(tài)代碼砂蔽、狀態(tài)描述的說明如下洼怔。
200 OK:客戶端請求成功。
400 Bad Request:客戶端請求有語法錯(cuò)誤左驾,不能被服務(wù)器所理解镣隶。
401 Unauthorized:請求未經(jīng)授權(quán),這個(gè)狀態(tài)代碼必須和WWW-Authenticate報(bào)頭域一起使用诡右。
403 Forbidden:服務(wù)器收到請求安岂,但是拒絕提供服務(wù),服務(wù)器通常會(huì)在響應(yīng)正文中給出不提供服務(wù)的原因。
404 Not Found:請求資源不存在帆吻,舉個(gè)例子:輸入了錯(cuò)誤的URL域那。
500 Internal Server Error:服務(wù)器發(fā)生不可預(yù)期的錯(cuò)誤,導(dǎo)致無法完成客戶端請求猜煮。
503 Server Unavailable:服務(wù)器當(dāng)前不能處理客戶端的請求次员,一段時(shí)間后可能恢復(fù)正常。
消息報(bào)頭:
同樣與請求頭類型王带,每一個(gè)報(bào)頭域都由名字+“:”+空格+值 組成淑蔚,消息報(bào)頭域的名字是大小寫無關(guān)的,常見消息報(bào)頭域名:
Content-Location:為了讓客戶端重定向到這個(gè)頁面新的位置,服務(wù)器端可以發(fā)回Location響應(yīng)報(bào)頭后使用重定向語句愕撰,讓客戶端去訪問新的域名所對應(yīng)的服務(wù)器上的資源;
Connection:不同于http1.0刹衫, http 1.1使用持久連接,就是服務(wù)器在發(fā)送響應(yīng)后仍然在一段時(shí)間內(nèi)保持這條連接搞挣,允許在同一個(gè)連接中存在多次數(shù)據(jù)請求和響應(yīng)带迟,keep_alive有效時(shí)間服務(wù)器配置參數(shù)自行決定;
WWW-Authenticate:WWW-Authenticate響應(yīng)報(bào)頭域必須被包含在401 (未授權(quán)的)響應(yīng)消息中囱桨,這個(gè)報(bào)頭域和前面講到的Authorization 請求報(bào)頭域是相關(guān)的仓犬,當(dāng)客戶端收到 401 響應(yīng)消息,就要決定是否請求服務(wù)器對其進(jìn)行驗(yàn)證舍肠。如果要求服務(wù)器對其進(jìn)行驗(yàn)證搀继,就可以發(fā)送一個(gè)包含了Authorization 報(bào)頭域的請求;
Cache-Control:緩存指令:no_cahe,no_store, no_tansform, max_age......貌夕,緩存指令為單向的律歼,且是獨(dú)立的(一個(gè)消息的緩存指令不會(huì)影響另一個(gè)消息處理的緩存機(jī)制)民镜,HTTP1.0使用的類似的報(bào)頭域?yàn)镻ragma啡专。
響應(yīng)正文:
服務(wù)器端返回給客戶端的數(shù)據(jù):html,j s 制圈。们童。畔况。。
繼續(xù)慧库,封裝好的標(biāo)準(zhǔn)的http響應(yīng)包跷跪,通過tcp ip協(xié)議,歷經(jīng)千辛萬苦齐板,終于送回到了客戶機(jī)瀏覽器吵瞻。響應(yīng)達(dá)到瀏覽器后,瀏覽器首先判斷狀態(tài)碼甘磨,如果是200橡羞,bing go直接進(jìn)入渲染過程;如果是3xx開頭則去響應(yīng)頭找到location域济舆,根據(jù)location的指引進(jìn)行跳轉(zhuǎn)卿泽,這里的跳轉(zhuǎn)需要開啟一個(gè)跳轉(zhuǎn)計(jì)數(shù)器,是為了避免兩個(gè)頁面或是多個(gè)頁面間形成循環(huán)跳轉(zhuǎn)滋觉,當(dāng)跳轉(zhuǎn)次數(shù)過多之后签夭,瀏覽器會(huì)報(bào)錯(cuò),同時(shí)停止椎侠。如果是400或500開頭的狀態(tài)碼第租,瀏覽器也會(huì)給出一個(gè)錯(cuò)誤頁面。
當(dāng)瀏覽器得到一個(gè)200響應(yīng)后肺蔚,接下來的面臨的問題就是多國語言語言的編碼解析了煌妈,響應(yīng)頭是一個(gè)ascii的標(biāo)準(zhǔn)字符集文本,但響應(yīng)的正文本質(zhì)是一個(gè)字節(jié)流宣羊,對于這一坨字節(jié)流璧诵,瀏覽器會(huì)首先看響應(yīng)頭中指定的encoding域,并按照指定的encoding解析字符仇冯;如果響應(yīng)頭中沒有encoding域之宿,瀏覽器會(huì)使用一些比較智能的方式【??,這么神奇苛坚?】比被,去猜測和判斷這一坨字節(jié)流應(yīng)該使用什么字符集解碼。
斷點(diǎn)2: HTTP ?Transfer_Encoding
"對于這一坨字節(jié)流泼舱,瀏覽器將根據(jù)響應(yīng)頭中指定的encoding域解析字符等缀。。娇昙。尺迂。。。"那么問題來了噪裕,響應(yīng)頭中的encoding域有Transfer-Encoding和Content-Encoding吧蹲盘,具體根據(jù)那個(gè)累,二者有什么關(guān)系嗎膳音?
為了解釋Transfer-Encoding召衔,事情得娓娓道來:HTTP 1.1協(xié)議響應(yīng)頭中默認(rèn)Keep-Alive,使得瀏覽器可以避開緩慢的三次握手祭陷、避免遇上TCP慢啟動(dòng)的擁塞適應(yīng)階段等苍凛,從而重用已開的空閑持久連接,這聽起來十分美妙兵志。但問題也隨之而來毫深,對于非持久連接,瀏覽器可以通過連接是否關(guān)閉來界定響應(yīng)實(shí)體的邊界毒姨;但對于持久性型連接哑蔫,顯然是行不通了,那么瀏覽器何時(shí)才能知道此連接是否仍有數(shù)據(jù)發(fā)送呢弧呐,難道只能癡癡的等闸迷?
要解決上面這個(gè)問題,你是不是想到了利用響應(yīng)頭中的Content-Length域判斷響應(yīng)實(shí)體已結(jié)束俘枫?但Content-Length反映的是真實(shí)響應(yīng)實(shí)體長度腥沽,在實(shí)際應(yīng)用中,有些響應(yīng)實(shí)體的長度并不易獲得鸠蚪,比如實(shí)體內(nèi)容由動(dòng)態(tài)語言生成今阳,如果要曉得實(shí)體長度,只能開一個(gè)足夠大的Buffer等內(nèi)容全部生成好后再計(jì)算【內(nèi)存開銷茅信,TTFB(Time To First Byte)】盾舌,畢竟Content-Length位于響應(yīng)頭中啊蘸鲸!妖谴。。酌摇。膝舅。。我們需要一種不依賴Content-Length獲取響應(yīng)正文的邊界的機(jī)制窑多。
Transfer-Encoding正是為此而來:Transfer-Encoding【傳輸編碼】仍稀,目前最新的HTTP規(guī)范里,只定義了一種傳輸編碼方式——分塊編碼(chunked)埂息。
分塊編碼相當(dāng)簡單技潘,即將報(bào)文實(shí)體拆分為一系列的分塊來傳輸:
在頭部加入Transfer-Encoding: chunked之后判沟,就代表這個(gè)報(bào)文采用了分塊編碼。這時(shí)崭篡,報(bào)文中的實(shí)體需要改為用一系列分塊來傳輸。每個(gè)分塊包含十六進(jìn)制的長度值和數(shù)據(jù)吧秕,長度值獨(dú)占一行琉闪,長度不包含其自身行結(jié)尾的 CRLF(\r\n)以及分塊數(shù)據(jù)結(jié)尾的 CRLF;最后一個(gè)分塊數(shù)據(jù)長度值須為0砸彬,對應(yīng)的分塊數(shù)據(jù)沒有內(nèi)容颠毙,表述實(shí)體結(jié)束,據(jù)某個(gè)大神用Node的net模塊創(chuàng)建了一個(gè) TCP Server的測試頁可供參考砂碉,其形式大致如下:
知曉了Transfer-Encoding的來龍去脈蛀蜜,我們接著說Encoding域的另一個(gè)相關(guān)字段:Content-Encoding(內(nèi)容編碼)。Content-Encoding增蹭,顧名思義滴某,就是對響應(yīng)正文進(jìn)行壓縮編碼,目的是為了優(yōu)化傳輸滋迈,比如gzip——壓縮文本文件霎奢。
Content-Encoding 和 Transfer-Encoding 二者是相輔相成,結(jié)合使用的饼灿,即對Transfer-Encoding的分塊再進(jìn)行Content-Encoding幕侠,比如某大神telnet請求測試頁面得到的http響應(yīng)包:
詳情可參見:https://imququ.com/post/transfer-encoding-header-in-http.html
解決了字符集的問題,接下來就是構(gòu)建dom樹了【瀏覽器內(nèi)核引擎如何構(gòu)建DOM樹碍彭?】晤硕,在html語言嵌套正常且規(guī)范的情況下,這種XML標(biāo)記的語言是比較容易構(gòu)建出一棵DOM樹的庇忌,當(dāng)然舞箍,對于互聯(lián)網(wǎng)上大量的不規(guī)范頁面,不同的瀏覽器應(yīng)該有自己的容錯(cuò)去處理皆疹。構(gòu)建出來的DOM本質(zhì)上是一棵抽象的邏輯樹创译,在構(gòu)建dom樹的過程中,如果遇到了由script標(biāo)簽包起來的js動(dòng)態(tài)腳本代碼墙基,那么會(huì)把代碼送到j(luò)s引擎里面去跑软族;如果遇到了style標(biāo)簽包圍起來css代碼,則會(huì)保存起來用于稍后的渲染残制。如果遇到了img等引用外部文件的標(biāo)簽立砸,那么瀏覽器會(huì)根據(jù)指定的url再次發(fā)起一個(gè)http請求將所需文件拉取回來〕醪瑁【值得一提的是颗祝,對于同一個(gè)域名下的下載過程來說,瀏覽器一般允許的并發(fā)請求是有限的,通陈荽粒控制在兩個(gè)左右搁宾,所以如果有很多圖片的話,一般出于優(yōu)化的目的倔幼,會(huì)把這些圖片使用一臺(tái)靜態(tài)文件的服務(wù)器來保存起來盖腿,負(fù)責(zé)響應(yīng),從而減少主服務(wù)器的壓力损同◆娓】
dom 樹構(gòu)造好了之后,就是根據(jù) dom 樹和 css 樣式表來構(gòu)造 render 樹了膏燃,這個(gè)才是真正的用于渲染到頁面上的一個(gè)一個(gè)的矩形框的樹茂卦,對于 render 樹上每一個(gè)框,需要確定他的 x y 坐標(biāo)组哩,尺寸等龙,邊框,字體伶贰,形態(tài)而咆,等等諸多方面的東西,render 樹一旦構(gòu)建完成幕袱,整個(gè)頁面也就準(zhǔn)備好了暴备,可以上菜了。
需要說明的是们豌,下載頁面涯捻,構(gòu)建 dom 樹,構(gòu)建 render 樹這三個(gè)步驟望迎,實(shí)際上并不是嚴(yán)格的先后順序的障癌,為了加快速度,提高效率辩尊,讓用戶不要等那么久涛浙,現(xiàn)在一般都并行的往前推進(jìn)的,現(xiàn)代的瀏覽器都是一邊下載摄欲,下載到了一點(diǎn)數(shù)據(jù)就開始構(gòu)建 dom 樹轿亮,也一邊開始構(gòu)建 render 樹,構(gòu)建了一點(diǎn)就顯示一點(diǎn)出來胸墙,這樣用戶看起來就不用等待那么久了我注。