創(chuàng)立一個網(wǎng)站得多少錢整站優(yōu)化關鍵詞推廣
DNS 的解析過程
- 瀏覽器緩存。當用戶通過瀏覽器訪問某域名時,瀏覽器首先會在自己的緩存中查找是否有該域名對應的 IP 地址(曾經(jīng)訪問過該域名并且沒有清空緩存)
- 系統(tǒng)緩存。當瀏覽器緩存中無域名對應的 IP 地址時,會自動檢測用戶計算機系統(tǒng)內(nèi)的 Hosts 文件中是否存在域名對應的 IP 地址
- 路由器緩存。當瀏覽器和系統(tǒng)緩存中均無域名對應的 IP 地址時,則會進入路由器緩存中查找(上述三步均為客戶端的 DNS 緩存 )
- ISP(互聯(lián)網(wǎng)服務提供商)DNS 緩存。當在用戶客戶端找不到域名對應的 IP 地址時,會進入 ISP DNS 緩存中查找。比如你用的是電信網(wǎng)絡,那么就會進入電信的 DNS 緩存服務器中查找
- 根域名服務器。當上述均未找到時,會進入根域名服務器中查找(全球僅有 13 臺根域名服務器,其中 1 個主根域名服務器,其余 12 臺為輔根域名服務器),根域名服務器在收到請求后會查看區(qū)域文件記錄,如果沒有,則將其管轄范圍內(nèi)的頂級域名服務器的 IP 地址告訴本地 DNS 服務器
- 頂級域名服務器。頂級域名服務器在收到請求后會查看域名文件記錄,如果沒有,則將其管轄范圍內(nèi)的主域名服務器的 IP 地址告訴本地 DNS 服務器
- 主域名服務器。主域名服務器在收到請求后會查詢自己的緩存,如果沒有,則進入下一級域名服務器中進行查找,重復該步驟直到找到正確的記錄
- 保存結果至緩存。本地域名服務器把返回的結果保存到緩存,以備下一次使用,同時將該結果反饋給客戶端,客戶端通過這個 IP 地址與 Web 服務器建立連接
TCP 為什么可靠?
- 超時重傳機制、快速重傳機制
- 流量控制(滑動窗口)
- 擁塞控制
超時重傳
就是在發(fā)送數(shù)據(jù)時,設定一個定時器(RTO),當超過指定的時間后,沒有收到對方的 ACK 確認應答報文,就會重發(fā)該數(shù)據(jù)。該計時器的時間一般是由當前網(wǎng)絡來決定的,一個 RTT 指的是當一個報文從發(fā)送到接收所需的時間,RTO 的取值是發(fā)送方嘗試發(fā)送幾個報文,然后取平均 RTT 時間來決定的。
TCP 會在以下兩種情況發(fā)生超時重傳:數(shù)據(jù)包丟失、確認應答丟失。
快速重傳
快速重傳的工作方式是當收到三個相同的 ACK 報文時,會在定時器過期之前,重傳丟失的報文段。
當接收方發(fā)現(xiàn)接收到的序列號不對的時候,會發(fā)送連續(xù)的三個 ACK 標志,告訴發(fā)送方這個報文在傳輸過程中出現(xiàn)了丟包。發(fā)送方如果接收到某個相同的序列號的三個 ACK 報文,那么此時立馬重發(fā)該報文,不會等待計時器的時間結束。
滑動窗口
TCP 引入了窗口這個概念。即使在往返時間較長的情況下,它也不會降低網(wǎng)絡通信的效率。
有了窗口,就可以指定窗口大小,窗口大小就是指無需等待確認應答,而可以繼續(xù)發(fā)送數(shù)據(jù)的最大值。
發(fā)送方通過維持一個發(fā)送滑動窗口來確保不會發(fā)生由于報文發(fā)送太快導致接收方無法及時處理的問題。此時發(fā)送方的報文分為四類:第一類是已經(jīng)發(fā)送并且得到接收方確認的報文;第二類是已經(jīng)發(fā)送但是沒有接收到確認的報文;第三類是發(fā)送方還沒發(fā)送,但是滑動窗口還足夠巨大,允許被發(fā)送的報文;第四類是還沒發(fā)送并且窗口已經(jīng)被占滿,不允許發(fā)送的報文。
流量控制
發(fā)送方不能無腦發(fā)數(shù)據(jù)給接收方,要考慮接收方的處理能力,否則就會導致觸發(fā)重發(fā)機制,從而導致網(wǎng)絡流量的無端浪費。
為了解決這種現(xiàn)象,TCP 提供一種機制可以讓發(fā)送方根據(jù)接收方的實際接收能力,控制發(fā)送的數(shù)據(jù)量,這就是所謂的流量控制。
擁塞控制
流量控制是避免發(fā)送方的數(shù)據(jù)填滿接收方的緩存,但是并不知道網(wǎng)絡中發(fā)生了什么。
一般來說,計算機網(wǎng)絡都處在一個共享的環(huán)境。因此也有可能會因為其他主機之間的通信使得網(wǎng)絡擁堵。
網(wǎng)絡出現(xiàn)擁堵時,如果繼續(xù)發(fā)送大量數(shù)據(jù)包,可能會導致數(shù)據(jù)包時延、丟失等,這時 TCP 就會重傳數(shù)據(jù),但是一重傳就會導致網(wǎng)絡的負擔更重,于是會導致更大的延遲以及更多的丟包,這個情況就會進入惡性循環(huán),被不斷地放大。
所以,TCP 不能忽略網(wǎng)絡上發(fā)生的事,它被設計成一個無私的協(xié)議,當網(wǎng)絡發(fā)送擁塞時,TCP 會自我犧牲,降低發(fā)送的數(shù)據(jù)量。
于是,就有了擁塞控制,控制的目的就是避免發(fā)送方的數(shù)據(jù)填滿整個網(wǎng)絡。
為了在發(fā)送方調(diào)節(jié)所要發(fā)送數(shù)據(jù)的量,定義了一個叫做擁塞窗口的概念。
擁塞窗口 cwnd (rwnd 表示接收窗口)是發(fā)送方維護的一個狀態(tài)變量,它會根據(jù)網(wǎng)絡的擁塞程度動態(tài)變化的。
擁塞控制主要是四個算法:慢啟動、擁塞避免、擁塞發(fā)生、快速恢復。
HTTP 的狀態(tài)碼
- 信息狀態(tài)碼:1 開頭
- 成功狀態(tài)碼:2 開頭
- 重定向狀態(tài)碼:3 開頭
- 客戶端錯誤狀態(tài)碼:4 開頭
- 服務端錯誤狀態(tài)碼:5 開頭
- 200 狀態(tài)碼:成功獲取資源(獲取到服務器資源或者請求強緩存)
- 304 狀態(tài)碼:請求協(xié)議緩存資源
- 301 狀態(tài)碼:永久重定向,被請求的資源已永久移動到新位置,并且將來任何對此資源的引用都應該使用本響應返回的若干個 URI 之一。如果可能,擁有鏈接編輯功能的客戶端應當自動把請求的地址修改為從服務器反饋回來的地址,除非額外指定,否則這個響應也可緩存
- 302 狀態(tài)碼:臨時重定向,請求的資源現(xiàn)在臨時從不同的 URI 響應請求。由于這樣的重定向是臨時的,客戶端應當繼續(xù)向原有地址發(fā)送以后的請求,只有在 Cache-Control 或 Expires 中進行了指定的情況下,這個響應才是可緩存的
- 401 狀態(tài)碼:未經(jīng)授權,請求要求身份驗證
GET 和 POST
- GET 一般是去請求獲取資源,POST 一般是發(fā)送數(shù)據(jù)到后臺使用
- GET 中的參數(shù)是拼接在 URL 后面的,不安全且長度有限制,POST 中的參數(shù)是放在 Request body 中的,相對安全且不受長度限制
- GET 在刷新瀏覽器或回退時不受影響,POST 在回退時會重新提交數(shù)據(jù)請求
- GET 請求可被緩存,POST 請求不會被緩存
- GET 請求只能進行 URI 編碼,POST 請求支持多種編碼方式
- GET 產(chǎn)生一個 TCP 數(shù)據(jù)包,POST 產(chǎn)生兩個 TCP 數(shù)據(jù)包
- 對于 GET 請求,瀏覽器會把 HTTP HEADER 和 DATA 一并發(fā)送出去,服務器響應 200 OK(返回數(shù)據(jù)),而對于 POST 請求,瀏覽器會先發(fā)送 HEADER,待服務器響應 100 CONTINUE 之后,瀏覽器再發(fā)送 DATA,服務器響應 200 OK(返回數(shù)據(jù))
其他請求方法
- GET:向指定的資源發(fā)出“顯示”請求
- POST:向指定資源提交數(shù)據(jù),請求服務器進行處理
- PUT:向指定資源位置上傳其最新內(nèi)容
- DELETE:請求服務器刪除 Request-URL 所標識的資源
- TRACE:回顯服務器收到的請求,主要用于測試或診斷
- CONNECT:HTTP/1.1 協(xié)議中預留給能夠?qū)⑦B接改為管道方式的代理服務器,通常用于 SSL 加密服務器的連接
TCP/IP 和 HTTP 協(xié)議的區(qū)別?
- TCP 處于傳輸層,HTTP 處于應用層
- HTTP 是基于 TCP 協(xié)議上的一種應用
- TCP 是底層協(xié)議,是定義數(shù)據(jù)傳輸和連接方式的規(guī)范
- HTTP 是應用層協(xié)議,是定義傳輸數(shù)據(jù)的內(nèi)容的規(guī)范
對稱加密和非對稱加密
- 對稱秘鑰加密,又稱私鑰加密。即信息的發(fā)送方和接收方用同一個秘鑰去加密和解密數(shù)據(jù),它的最大優(yōu)勢是加/解密速度快,適合對大數(shù)據(jù)量進行加密,但秘鑰管理困難
- 非對稱秘鑰加密,又稱公鑰加密。它需要使用一對秘鑰來分別完成加密和解密的操作,一個公開發(fā)布,即公開秘鑰,另一個由用戶自己秘密保存,即私有秘鑰,信息發(fā)送者用公開秘鑰去加密,而信息接收者用私有秘鑰去解密
- 從功能和安全角度而言,非對稱加密比對稱加密強大,但加/解密速度卻比對稱秘鑰慢得多
HTTP 長連接和短連接的區(qū)別?
- HTTP 協(xié)議是無狀態(tài)的,無狀態(tài)是指 HTTP 協(xié)議對事務處理沒有記憶能力,服務器不知道客戶端的狀態(tài),每次發(fā)送請求都得重新建立連接
- HTTP/1.0 協(xié)議默認是短連接,客戶端和服務器每進行一次 HTTP 請求就需要建立一次連接,結束后就中斷連接,在訪問網(wǎng)絡中含有其他的 Web 資源時,每次去訪問一個 Web 資源,瀏覽器就會新建一個 HTTP 會話
- HTTP/1.1 協(xié)議默認是長連接,保持其連接的持續(xù)性,在使用 HTTP 長連接的時候,HTTP 對應的響應頭會有 Connection: keep-alive
- 長連接:當瀏覽器打開網(wǎng)頁后,客戶端和服務器之間用于傳輸 HTTP 數(shù)據(jù)的 TCP 連接通道不會關閉,等客戶端再次訪問服務器時,會繼續(xù)使用已存在的連接。但是這個 Connection: keep-alive 也不會永遠保持連接,保持的時間是由服務器設定的,實現(xiàn)長連接需要客戶端和服務端都支持
- HTTP 協(xié)議的長連接和短連接實際上是 TCP 協(xié)議的長連接和短連接
輪詢、長輪詢、長連接、WebSocket 的區(qū)別?
- 輪詢:客戶端定時向服務器發(fā)送請求,服務器收到請求后立馬返回響應信息并關閉連接。優(yōu)點是后端程序編寫比較容易,缺點是請求中有大半是無用的,會浪費帶寬和服務器資源。這種方式由于需要不斷建立 HTTP 連接,嚴重浪費了服務器和客戶端的資源,短輪詢不適合那些同時在線用戶數(shù)量比較大,并且很注重性能的 Web 應用
- 長輪詢:客戶端向服務器發(fā)送請求,服務器收到請求后 hold 住連接,直到有新消息返回響應信息時(或到了設定的超時時間時)才關閉連接,客戶端處理完響應信息后再向服務器發(fā)送新的請求。優(yōu)點是減少很多不必要的 HTTP 請求次數(shù),相比之下節(jié)約了資源,缺點是服務器 hold 連接會消耗資源,需要同時維護多個線程,而服務器所能承受的 TCP 連接數(shù)是有上限的,這種輪詢很容易把連接數(shù)占滿,例如:webQQ、facebook IM
- 長連接:HTTP/1.1 通過使用
Connection: keep-alive
進行長連接,HTTP/1.1 默認進行持久連接,在一次 TCP 連接中可以完成多個 HTTP 請求,但是每個請求仍然要單獨發(fā) HEADER - WebSocket:WebSocket 協(xié)議本質(zhì)上是一個基于 TCP 的協(xié)議,為了建立一個 WebSocket 連接,客戶端瀏覽器首先要向服務器發(fā)送一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,它包含了一些附加頭信息,其中附加頭信息
upgrade: WebSocket
表明這是一個申請協(xié)議升級的 HTTP 請求,服務器解析這些附加的頭信息,然后產(chǎn)生響應信息返回給客戶端,客戶端和服務器的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由地傳遞信息,并且這個連接會一直持續(xù)到客戶端或服務器任意一方主動關閉連接 - 兼容性:短輪詢 > 長輪詢 > 長連接 > WebSocket
- 性能:WebSocket > 長連接 > 長輪詢 > 短輪詢
Session、Cookie 和 Application 的區(qū)別?
- Cookie:Cookie 存放在客戶端中,因此有效時間以客戶端的時間為準,可以手動設置,如果沒有指定 Cookie 對象的有效期,則 Cookie 對象只存在客戶端的內(nèi)存,當瀏覽器關閉時,Cookie 就會失效,Cookie 中保存的是字符串,支持跨域名訪問
- Session:Session 是服務器技術,利用這個技術,服務器可以把與會話相關的數(shù)據(jù)寫到一個代表會話的 Session 對象中,用來存儲用戶跨網(wǎng)頁程序的變量,只針對單一用戶,Session 的有效期可以自己設置,Session 保存的是對象,不支持跨域名訪問
- Application:多個用戶共享的應用級別的作用域,在服務器,相比前兩者它的存在時間最長,只有當關閉服務器時才會失效
Cookie 是如何工作的?
當客戶端訪問服務器時,服務器通過 Cookie 構造器構造一個 Cookie 實類,然后服務器在響應信息頭中附帶 Cookie 實類到客戶端,并保存在客戶端內(nèi)存中,在 Cookie 生命周期內(nèi),以后的每次請求都會攜帶這個 Cookie。
Cookie 和 Session 是如何記住登錄狀態(tài)的?
當 Session 啟動時,服務器會生成一個唯一值,稱為 sessionid,服務器會開辟一塊內(nèi)存,對應該 sessionid,服務器再將該 sessionid 寫入瀏覽器的 Cookie,服務器內(nèi)有一進程,監(jiān)視所有 Session 的活動狀態(tài),如果有 Session超時或主動關閉,服務器就釋放該內(nèi)存塊。當瀏覽器請求服務器時,服務器會先查看請求頭 Cookie 中是否有 seesionid,如果有,就檢查該 sessionid 對應的內(nèi)存是否有效,有效則讀取內(nèi)存中的值,無效則建立新的 Session。
當 Cookie 被禁止時,如何保存登錄狀態(tài)?
保存登陸狀態(tài)的關鍵不是 Cookie,而是通過 Cookie 保存和傳送 sessionid 的值,我們可以通過 encodeURL 編碼 URL,或者 access token,然后將其保存到 localstorage 即可。
什么是死鎖以及死鎖的解決辦法?
- 死鎖:是指兩個或者兩個以上的進程在執(zhí)行過程中,由于競爭資源或者彼此通信而造成的一個阻塞現(xiàn)象,若無外力作用,它們都將無法繼續(xù)推進下去
- 互斥條件:進程對所分配到的資源具有排它性,即一個資源只能被一個進程所占用,直到進程被釋放
- 請求和保持條件:當進程因請求資源而進入阻塞時,對方獲得的資源保持不放
- 不剝奪條件:進程已獲得的資源在未使用完之前不能被剝奪,只能在使用完時由自己釋放
- 環(huán)路等待條件:在發(fā)生死鎖時,所等待的進程必定會形成一個環(huán)路(類似于死循環(huán)),造成永久阻塞
- 解決辦法:破壞任意的必要條件即可
Web 安全防范
- XSS:跨站腳本攻擊,它指的是攻擊者往 Web 頁面里面插入惡意代碼腳本,而網(wǎng)站在設計輸入輸出部分時,沒有對用戶的輸入內(nèi)容進行過濾,當用戶瀏覽網(wǎng)站時,嵌入的 Web 腳本代碼就會被執(zhí)行,從而達到惡意攻擊用戶的特殊目的。防范手段有:設置
HttpOnly
,XSS 攻擊主要是想獲取到 Cookie 中的 sessionid 并劫持對話,而當 Cookie 設置為HttpOnly
屬性時,js 腳本將無法獲取到 Cookie 信息;輸入輸出檢查過濾;HTML 代碼轉譯 - CSRF:跨站請求偽造攻擊,它通過偽裝來自信任用戶的請求來攻擊信任網(wǎng)絡,或者理解為盜用用戶的身份,以用戶的名義來進行某些非法操作。防范手段有:驗證 HTTP
Referer
字段,在 HTTP 請求頭中有一個Referer
字段,它記錄了該 HTTP 請求的來源地址,只需要核對Referer
字段是否是合法來源即可,注意在 IE6 中可以修改Referer
值;在請求地址中添加token
,可以在 HTTP 請求中以參數(shù)加入一個隨機的token
,并在服務器上建立一個攔截器來驗證這個token
;在 HTTP 頭中自定義屬性并驗證,其方法和 token 差不多,只是將其添加到 HTTP 頭自定義屬性中 - SQL 注入:攻擊者在 HTTP 請求中注入惡意的 SQL 代碼,服務器使用參數(shù)構建數(shù)據(jù)庫 SQL 命令時,惡意的 SQL 會被一起構建,從而達成某些非法的操作。防范手段有:有效性的核查和過濾;限制字符串輸入長度;服務器使用預編譯的 PrepareStatement
為什么瀏覽器會產(chǎn)生同源策略?
同源策略的目的是為了限制不同源的 document 或者腳本之間互相訪問,以免造成干擾和混亂。如果沒有限制,那么瀏覽器中的 Cookie 等數(shù)據(jù)就可以被任意讀取,不同域下的 DOM 任意操作,ajax 任意請求其他網(wǎng)站的數(shù)據(jù)包括隱私數(shù)據(jù)。
瀏覽器的緩存機制
- 強緩存:判斷是否是緩存的依據(jù),來自于是否超出某個時間或者某個時間段,而不關心服務器文件是否已經(jīng)更新。強緩存主要分為兩種:
Expires
和Cache-Control
,Expires
保存的是一個絕對時間,即緩存過期時間,它是相對服務器時間來定的,瀏覽器會判斷本地時間和Expires
來確定是否要訪問本地緩存,由于服務器時間和客戶端時間在很多時候是不相等的,所以有可能會造成不確定性,現(xiàn)在幾乎很少使用Expires
;Cache-control
保存的是一個相對時間,可以通過設置max-age
來確定文件的緩存時間,其原理和Expires
一樣,當兩者同時存在時,Cache-Control
的優(yōu)先級高于Expires
- 協(xié)商緩存:由服務器來確定緩存資源是否可用,協(xié)商緩存主要分為兩種:
Last-Modify
和ETag
,Last-Modify
:瀏覽器第一次訪問服務器的時候,會在返回的請求頭中加上一個Last-Modified
字段,它是資源的最后修改時間,當瀏覽器再次訪問時,其請求頭中會包含一個If-Modified-Since
字段,服務器判斷它是否相同再確定是返回 304 還是 200;ETag
:其原理和Last-Modify
幾乎一樣,只是它返回的是一般是哈希值或是對該資源的 md5 值(生成規(guī)則由服務器決定),它會在請求頭攜帶If-None-Match
字段,如果兩者同時存在,ETag
的優(yōu)先級高于Last-Modify
,Last-Modified
只能精確到秒,秒內(nèi)的內(nèi)容更新只有ETag
才能檢查,文件有時會定時重新生成相同的內(nèi)容,Last-Modified
不能很好地識別,ETag
每次服務器生成都需要進行讀寫操作,而Last-Modified
只需要讀取操作,Etage
的消耗更大 - 如果有強緩存,且強緩存未過期,瀏覽器會優(yōu)先訪問強緩存,并返回 200,在沒有強緩存或者強緩存過期的情況下才會訪問協(xié)商緩存,再根據(jù)
Etag
或Last-Modified
返回 304 或 200
瀏覽器從輸入 URL 到頁面渲染的過程
- 瀏覽器輸入 URL 并回車
- 瀏覽器查找 URL 是否存在未過期的緩存
- 域名解析 URL 對象的 IP
- 根據(jù) IP 和服務器建立 TCP 三次握手連接
- 客戶端發(fā)送 HTTP 請求
- 服務器處理請求并返回響應報文
- 瀏覽器接收 HTTP 響應
- 構造 DOM 樹、渲染頁面
- 四次揮手關閉 TCP 連接
TCP 建立連接的過程
TCP/IP 三次握手
- 第一次握手。建立連接時,客戶端發(fā)送 SYN 包(seq=x)到服務器,進入
SYNC_SEND
狀態(tài),等待服務器確認 - 第二次握手。服務器收到 SYN 包,必須先確認客戶端的 SYN,同時服務器發(fā)送 SYN 包(ack=x+1,seq=y),進入
SYN_RECV
狀態(tài) - 第三次握手??蛻舳耸盏椒掌鞯?SYN + ACK 包,并向服務器發(fā)送 ACK 確認包(ack=y+1),客戶端和服務器都進入
ESTABLISHED
狀態(tài)
如果建立連接之后客戶端出現(xiàn)故障
TCP 設有一個 ?;钣嫊r器
,服務器在每收到一次客戶端的請求后都會重置該計時器,時間通常設置為 2 小時,若 2 小時后還沒有收到客戶端的任何數(shù)據(jù),服務器就會發(fā)送一個探測報文段,之后每隔 75s 再發(fā)送一次,若連續(xù)發(fā)送 10 個探測報文段都仍未有響應,那么服務器便認為客戶端出現(xiàn)故障并主動關閉連接。
TCP/IP 四次揮手
- 第一次揮手??蛻舳税l(fā)送(FIN=1,seq=u),進入
FIN-WAIT-1
狀態(tài) - 第二次揮手。服務器收到報文后,發(fā)送確認報文(ACK=1,ack=u+1),進入
CLOSE_WAIT
狀態(tài) - 第三次揮手。服務器發(fā)送(FIN,seq=w)用來關閉客戶端與服務器之間的數(shù)據(jù)傳送,進入
LAST_ACK
狀態(tài) - 第四次揮手??蛻舳耸盏?FIN 包后進入
TIME_WAIT
狀態(tài),并發(fā)送 ACK 確認報文(ack=w+1)給服務器,服務器接收后進入CLOSED
狀態(tài),完成四次揮手
為什么客戶端發(fā)送完最后一個 ACK 包后并不會立刻進入 CLOSED
狀態(tài),而是會等待 2MSL(最長報文段壽命)
如果網(wǎng)絡是不可靠的,那么有可能最后一個 ACK 會丟失,而服務器將會不斷重復地發(fā)送 FIN 片段,所以客戶端不能立即關閉,它必須確認服務器已經(jīng)接收到了該 ACK,TIME_WAIT
狀態(tài)就是用來重發(fā)可能丟失的 ACK 報文,客戶端會設置一個計時器并等待 2MSL 的時間,如果在該時間內(nèi)再次收到 FIN,那么客戶端就會重新發(fā)送一個 ACK 并再次等待 2MSL。所謂的 MSL就是一個片段在網(wǎng)絡中的最大存活時間,2MSL 就是發(fā)送和回復所需要的最大時間,如果直到 2MSL 時間后客戶端都沒有再次收到 FIN,那么客戶端就判斷 ACK 已經(jīng)被成功接收并結束 TCP 連接。
為什么要三次握手
主要是為了防止失效的連接請求報文段被服務器接收,從而產(chǎn)生錯誤,如果建立連接只需要兩次握手,客戶端沒有太大改變,還是需要獲得服務器的響應后才進入 ESTABLISHED
狀態(tài),而服務器則是在接收到連接請求后就進入 ESTABLISHED
狀態(tài)。此時如果網(wǎng)絡阻塞導致客戶端發(fā)送的連接請求遲遲不到服務器,客戶端便會超時重發(fā),這時如果服務器正確接收并響應了,雙方便開始通信,通信結束后釋放連接。此時如果那個失效的連接請求抵達了服務器,由于只存在兩次握手,那么服務器就會再次進入 ESTABLISHED
狀態(tài),等待發(fā)送數(shù)據(jù)或主動發(fā)送請求,但此時客戶端已經(jīng)進入 CLOSED
狀態(tài),那么服務器就會一直等待下去,浪費連接資源。
為什么要四次揮手
四次揮手中的第二次和第三次是分開的,而不是像三次握手那樣一起發(fā)送,因為服務器發(fā)送報文段二的時候只是確認客戶端發(fā)送的結束報文,并不代表自身的數(shù)據(jù)已經(jīng)傳輸完畢,由于時間是不確定的,如果硬是等到自身數(shù)據(jù)傳輸完畢后再將確認報文 ACK 和自身結束報文 FIN 一起發(fā)送,可能會導致客戶端超時重傳等問題,造成資源浪費。
什么是線程,線程和進程的區(qū)別?
- 進程和線程都是一個時間段的描述,是 CPU 工作時間段的描述,它們只是顆粒大小不同
- 進程是資源分配和調(diào)度的一個獨立單位,而線程是 CPU 調(diào)用的基本單位
- 同一個進程中可以包括多個線程,并且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包括一個線程
- 進程的創(chuàng)建調(diào)用 fork 或者 vfork,而線程創(chuàng)建調(diào)用 pthread_create,進程結束后它擁有的所有線程都將銷毀,而線程結束不會影響同個進程中的其他線程
- 線程是輕量級的進程,它的創(chuàng)建和銷毀所需的時間比進程小很多,操作系統(tǒng)中所有的執(zhí)行功能都是創(chuàng)建線程去完成的
- 線程中執(zhí)行時一般都要進行同步和互斥,因為它們共享同一進程的所有資源
- 線程有自己的私有屬性:TCB、線程 id、寄存器、硬件上下文,而進程也有自己的私有屬性:進程控制塊 PCB,這些私有屬性是不被共享的,是一個進程或一個線程的標志
let、const 和 var 的區(qū)別?
- var 聲明的變量會掛載在 window 上,而 let 和 const 聲明的變量不會
- var 聲明的變量存在變量提升,let 和 const 不存在變量提升
- let 和 const 聲明形成塊狀作用域
- 同一作用域下,let 和 const 不能聲明同名變量,而 var 可以
- const 一旦聲明必須賦值,且聲明后不能修改,如果聲明的是復合類型數(shù)據(jù),則可以修改其屬性
介紹一下 promise 相關的東西
- pedding、fulfilled、rejected(未決定、履行、拒絕),同一時間只能存在一種狀態(tài),且狀態(tài)一旦改變就不能再變
- 初始化,狀態(tài):pedding
- 當調(diào)用 resolve(成功),狀態(tài):pedding -> fulfilled
- 當調(diào)用 reject(失敗),狀態(tài):pedding -> rejected
js 判斷類型的方法
- typeof:只能判斷基本數(shù)據(jù)類型,判斷引用類型都是 object
- instanceof:只能進行類型的對比,不能進行類型的判斷,測試后者是否是前者的原型鏈上的構造函數(shù)
- Object.prototype.toString.call(arr):能較為準確判斷數(shù)據(jù)類型,測試該該對象是否是括號中函數(shù)的原型
New 一個對象的過程
- 創(chuàng)建一個空對象 obj
- 將 obj 的 prototype 屬性指向構造函數(shù)原型(prototype)
- 將構造函數(shù)內(nèi)部的 this 綁定在新對象 obj 上,執(zhí)行構造函數(shù)(用 apply 方法綁定 this)
- 若構造函數(shù)沒有返回其他對象,則返回該新建的 obj,否則返回引用類型的值
原型鏈
_proto_
屬性(隱式原型):它的值就是它所對應的原型對象,作用是當訪問一個對象的屬性時,如果該對象內(nèi)部不存在這個屬性,那么就會去它的_proto_
屬性所指向的那個對象里找,一直向上找直到_proto_
屬性的終點 null,再往上找相當于在 null 上取值,會報錯,通過_proto_
屬性將對象連接起來的這條鏈路即我們所說的原型鏈Prototype
屬性(顯示原型):是函數(shù)的原型對象,作用就是讓該函數(shù)所實例化的對象們可以找到公用的屬性和方法Constructor
屬性:是指向該對象的構造函數(shù),所有函數(shù)的最終構造函數(shù)都是 Function
JSON.parse(JSON.stringify()) 深拷貝的弊端
- JSON.parse(JSON.stringify()) 實現(xiàn)深拷貝,其原理就是利用 JSON.Stringify 將 js 對象序列化,再反序列化還原對象,序列化的作用是存儲(對象本身存儲的只是一個地址映射,如果斷電則對象將不復存在,因此需要將對象的內(nèi)容轉換成字符串的形式再保存在磁盤上)和傳輸
- 如果 obj 里面有時間對象,用其處理后返回的只是字符串形式的數(shù)據(jù)
- 如果 obj 里有 RegExp、Error 對象,則序列化的結果會變成空對象
- 如果 obj 里有函數(shù)、undefined,則序列化的結果會把函數(shù)或 undefined 丟失
- 如果 obj 里有 NaN、Infinity 和 -Infinity,則序列化的結果會變成 null
- JSON.stringify 只能序列化可枚舉的自由屬性,例如:如果 obj 中的對象是由構造函數(shù)生成的,則實行深拷貝后會丟失對象的 constructor
- 如果對象中存在循環(huán)引用的情況也無法正確實現(xiàn)深拷貝
深拷貝
使用遞歸的方式實現(xiàn)深拷貝
function deepClone1(obj) {// 判斷要進行深拷貝的是數(shù)組還是對象, 是數(shù)組的話進行數(shù)組拷貝, 對象的話進行對象拷貝var objClone = Array.isArray(obj) ? [] : {};if (obj && typeof obj === "object") {for (key in obj) {if (obj.hasOwnProperty(key)) {if (obj[key] && typeof obj[key] === "object") {objClone[key] = deepClone1(obj[key]);} else {objClone[key] = obj[key];}}}}return objClone;
}
通過 JSON 對象實現(xiàn)深拷貝
var _obj = JSON.parse(JSON.stringify(obj))
通過 Jquery 的 extend 方法實現(xiàn)深拷貝
$.extent(true, {}, obj);
通過 Object.assign() 拷貝
// 當對象中只有一級屬性沒有二級屬性的時,此方法為深拷貝, 但是對象中有對象的時候, 此方法在二級屬性以后就是淺拷貝
var _obj = Object.assign({}, obj);
Lodash 函數(shù)庫實現(xiàn)深拷貝
_.CloneDeep()
兩個對象比較
function diff(val1, val2) {var o1 = val1 instanceof Object;var o2 = val2 instanceof Object;if (!o1 || !o2) {return val1 === val2;}if (Object.keys(val1).length !== Object.keys(val2).length) {return false;}for (var o in val1) {var t1 = val1[o] instanceof Object;var t2 = val2[o] instanceof Object;if (t1 && t2) {diff(t1, t2)} else if (val1[o] !== val2[o]) {return false;}}return true;
}
HTTPS 的工作流程
- 客戶端(瀏覽器)訪問 https://www.baidu.com 百度網(wǎng)站
- 百度服務器返回 HTTPS 使用的 CA 證書
- 瀏覽器驗證 CA 證書是否為合法證書
- 驗證通過,證書合法,生成一串隨機數(shù)并使用公鑰(證書中提供的)進行加密
- 發(fā)送公鑰加密后的隨機數(shù)給百度服務器
- 百度服務器拿到密文,通過私鑰進行解密,獲取到隨機數(shù)(公鑰加密,私鑰解密,反之也可以)
- 百度服務器把要發(fā)送給瀏覽器的內(nèi)容,使用隨機數(shù)進行加密后傳輸給瀏覽器
- 此時瀏覽器可以使用隨機數(shù)進行解密,獲取到服務器的真實傳輸內(nèi)容。
這就是 HTTPS 的基本運作原理,使用對稱加密和非對稱機密配合使用,保證傳輸內(nèi)容的安全性。