计算机网络面试题汇总(什么是计算机)
TCP/IP體系結構
1. TCP/IP的四層模型指的是哪些?
TCP/IP按照層次劃分,可以分為以下四層 :
①網絡接口層:對應物理層和數據鏈路層
②網絡層
③傳輸層
④應用層:包括會話層、表示層、應用層
各層舉例如下表所示:
| 網絡接口層 | 控制操作系統,硬件設備驅動.網絡適配器等等硬件設備 |
|---|---|
| 網絡層 | IP |
| 傳輸層 | TCP(傳輸控制協議),UDP(用戶數據報協議) |
| 應用層 | FTP(文件傳輸協議),DNS(域名系統),HTTP(超文本傳輸協議) |
2. OSI的七層模型
- 物理層:在物理信道上實現原始比特流的傳輸。(以太網, IEEE 802.2 等)
- 數據鏈路層:實現無差錯地將數據幀(將網絡層的數據封裝成數據幀,便于物理層傳輸)從一個節點傳送到下一個相鄰節點。(Wi-Fi(IEEE 802.11) , WiMAX(IEEE 802.16), GPRS, HDLC, PPP 等協議)
- 網絡層:實現將數據分組從源站通過網絡傳送到目的站,即網絡上一臺主機與另一臺主機之間的數據傳輸。(IP, ICMP, IGMP, ARP, RARP, OSPF 等協議)
- 傳輸層:實現源端到目的端數據的傳輸,即某主機的某進程與另一臺主機的某進程之間的數據傳輸。(TCP, UDP 等協議)
- 會話層:實現在不同機器上用戶建立、維護和終止會話關系。即會話層對會話提供控制管理服務、會話同步服務等。(ZIP, ASP, SSH 等協議)
- 表示層:確保各種通信設備能夠互相操作,不及考慮其數據的內部表示。即確保即使各種通信設備其數據的內部表示不同,但仍然能相互正確操作。(SSL等協議)
- 應用層:使用戶能夠訪問網絡,為各類應用提供相應的服務、提供各種用戶接口支持服務。應用層不是應用程序,應用層是一個為應用程序提供各類應用支持的服務層。(HTTP, FTP, SMTP, POP3, DHCP, DNS等協議)
五層模型的作用 : (字節跳動)
物理層 : 在物理信道中實現原始的比特流的傳輸(物理層協議例如以太網,IEEE 808.2等等)
數據鏈路層 : 實現將數據幀(將網絡層的數據封裝成數據幀),從一個節點傳送到另一個節點
網絡層 : 實現將數據分組從源站通過網絡傳送到目的站,即我們說的網絡上一臺主機與另一臺主機的數據傳輸,其中IP,ARP協議即為網絡層協議
傳輸層 : 實現源端到目的端數據的傳輸,即某主機的某個進程與另一個主機的某一個進程之間的數據傳輸,TCP,UDP
應用層 : 是用戶能夠訪問網絡,為各類應用提供相應的服務,提供各種用戶接口支持服務
在七層模型中,還多出來了兩層 :
表示層 : 確保各種通信設備能夠互相操作,不及考慮其數據的內部表示。即確保即使各種通信設備其數據的內部表示不同,但仍然能相互正確操作。(SSL等協議)
會話層:實現在不同機器上用戶建立、維護和終止會話關系。即會話層對會話提供控制管理服務、會話同步服務等。(ZIP, ASP, SSH 等協議)
TCP、UDP的區別
TCP和UDP是TCP/IP體系結構運輸層中的兩個重要協議
TCP(Transmission Control Protocol):傳輸控制協議
UDP(User Datagram Protocol):用戶數據報協議
(1)TCP:面向有連接,可靠的,速度慢,效率低。
(2)UDP:面向無連接, 不可靠,速度快,效率高。
當進程需要傳輸可靠的數據時應使用TCP,當進程需要高效傳輸數據,可以忽略可靠性時應使用UDP協議
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2M2v5aZL-1632465301638)(.\imgs\TCP和UDP的區別.jpg)]
注意 : UDP的不可靠性就在于它的面向無連接的,不需要建立連接,就可以發送數據,即UDP只會把想發的數據報文一股腦的丟給對方,并不在意數據有無安全完整到達.
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-adxLq68d-1632465301641)(.\imgs\UDP.gif)]
如何在應用層保證udp可靠傳輸
因為udp是面向無連接的,不能保證傳輸的可靠性,此時我們只能在應用層實現可靠傳輸
目前有如下開源程序利用udp實現了可靠的數據傳輸。分別為RUDP、RTP、UDT
RUDP
? RUDP 提供一組數據服務質量增強機制,如擁塞控制的改進、重發機制及淡化服務器算法等,從而在包丟失和網絡擁塞的情況下, RTP 客戶機(實時位置)面前呈現的就是一個高質量的 RTP 流。在不干擾協議的實時特性的同時,可靠 UDP 的擁塞控制機制允許 TCP 方式下的流控制行為。
RTP
? 實時傳輸協議(RTP)為數據提供了具有實時特征的端對端傳送服務,如在組播或單播網絡服務下的交互式視頻音頻或模擬數據。應用程序通常在 UDP 上運行 RTP 以便使用其多路結點和校驗服務;這兩種協議都提供了傳輸層協議的功能。但是 RTP 可以與其它適合的底層網絡或傳輸協議一起使用。如果底層網絡提供組播方式,那么 RTP 可以使用該組播表傳輸數據到多個目的地。
RTP 本身并沒有提供按時發送機制或其它服務質量(QoS)保證,它依賴于底層服務去實現這一過程。 RTP 并不保證傳送或防止無序傳送,也不確定底層網絡的可靠性。 RTP 實行有序傳送, RTP 中的序列號允許接收方重組發送方的包序列,同時序列號也能用于決定適當的包位置,例如:在視頻解碼中,就不需要順序解碼。
UDT
? 基于UDP的數據傳輸協議(UDP-basedData Transfer Protocol,簡稱UDT)是一種互聯網數據傳輸協議。UDT的主要目的是支持高速廣域網上的海量數據傳輸,而互聯網上的標準數據傳輸協議TCP在高帶寬長距離網絡上性能很差。顧名思義,UDT建于UDP之上,并引入新的擁塞控制和數據可靠性控制機制。UDT是面向連接的雙向的應用層協議。它同時支持可靠的數據流傳輸和部分可靠的數據報傳輸。由于UDT完全在UDP上實現,它也可以應用在除了高速數據傳輸之外的其它應用領域,例如點到點技術(P2P),防火墻穿透,多媒體數據傳輸等等
TCP流量控制
流量控制:讓發送方的發送速率不要太快,要讓接收方來得及接收
利用滑動窗口機制可以很方便地在TCP連接上實現對發送方的流量控制
假設A發送的每個TCP數據報文段可攜帶100字節數據;
在A和B建立連接時,B告訴A:我的接收窗口為400;
于是,A將自己的發送窗口也設置為400,也就是能發送1-400的數據
當B又有存儲空間時,會向A發送窗口值,則A又可以繼續發送數據了
但是如果B發送的這個窗口值丟失,就會造成死鎖
解決:
當A收到的窗口值為0時就開啟一個持續計時器,當持續計時器超時,會向B發送一個零窗口探測報文
如果B返回的窗口還是0,A就重新啟動持續計時器
零窗口探測報文也會丟失,解決:零窗口探測報文也存在一個重傳計時器
在某段時間,若對網絡中某一資源的需求超過了該資源所能提供的可用部分,網絡性能就要變壞,這種情況就叫做網絡擁塞.
TCP擁塞控制
若對網絡中某一資源的需求超過了該資源所能提供的可用部分,網絡性能就會變壞,這種情況叫網絡擁塞。
網絡擁塞的原因主要有以下三點:
- 處理器的速度太慢
- 線路容量的限制
- 節點輸出包的能力小于輸入包的能力
而我們所說的TCP的擁塞控制和流量控制的原理是相關的 :
流量控制在數據鏈路層對一條通信路徑上的流量進行控制,其的是保證發送者的發送速度不超過接收者的接收速度,它只涉及一全發送者和一個接收者,是局部控制。
擁塞控制是對整個通信子網的流量進行控制,其目的是保證通信子網中的流量與其資源相匹配,使子網不會出現性能下降和惡化、甚至崩潰,是全局控制。
擁塞控制的目的:
- 防止由于過載而使得吞吐量下降,損失效率
- 合理分配網絡資源
- 避免死鎖
- 匹配傳輸速度
擁塞控制的方法:
開環控制: 開環控制的思想是通過良好的設計避免擁塞問題的出現,確保擁塞問題在開始時就不可能發生。開環控制方法包括何時接受新的通信何時丟棄包、丟棄哪些包。其特點是在作出決定時不考慮網絡當前的狀態
閉環控制: 閉環控制的思想是反饋控制。即通過將網絡工作的動態信息反饋給網絡中節點的有關進程,節點根據網絡當前的動態信息,調整轉發數據包的策略。閉環控制過程包括三部分:
① 監視系統 檢測網絡發生或將要發生擁塞的時間和地點
② 報告 將監視中檢測到的信息傳送到可以進行擁塞控制的節點
③ 決策 調整系統的操作行為,以解決問題
擁塞控制的常見算法:
- 1.慢開始 : 先指數級增長連接,到達閾值時,保持不變…
- 2.擁塞控制 : 每一次只增1(線性增長)
- 3.快重傳 : 有沒有在規定時間內返回響應…
- 4.快恢復
發送方維護一個擁塞窗口的狀態變量cwnd,其值取決于網絡的擁塞程度,且動態變化。發送方將擁塞窗口作為發送窗口swnd = cwnd。發送方維護一個慢開始門限ssthresh狀態變量。
擁塞窗口的維護原則:只要網絡沒有出現擁塞,擁塞窗口就增大;出現擁塞,擁塞窗口就減小。
判斷是否出現網絡擁塞的依據:判斷有沒有按時收到確認報文。
cwnd < ssthresh慢開始
cwnd >=ssthresh擁塞控制
1.慢開始
初始擁塞窗口cwnd=1,發送方只能發送1個數據報文(cwnd是幾,就發送幾個),接收方收到報文,發送1個確認報文;
擁塞窗口變為cwnd=2,發送方發送2個數據報文,接收方收到報文,發送2個確認報文;
擁塞窗口cwnd=4。發送方發送4個報文數據,接收方收到報文,發送4個確認報文;
擁塞窗口cwnd=8 …
…
擁塞窗口cwnd=16(cwnd按指數增長)
當擁塞窗口值>=慢開始門限時,改為擁塞控制算法
2.擁塞控制
擁塞控制:cwnd只能每次線性+1。
擁塞窗口cwnd=16。發送方發送16個報文數據,接收方收到報文,發送1個確認報文;
擁塞窗口cwnd=17。發送方發送17個報文數據,接收方收到報文,發送1個確認報文;
擁塞窗口cwnd=18。發送方發送18個報文數據,接收方收到報文,發送1個確認報文;
…
擁塞窗口cwnd=18(cwnd線性增長)
如果發送方發送了24個報文,但是只接收到了20個確認報文,丟失的4個報文的重傳計時器超時了,
發送方判斷出現擁塞,重置ssthresh=cwnd/2;cwnd=1
3.快重傳-快恢復
快重傳-快恢復:使發送方盡快重傳,而不是等重傳計時器超時再重傳。
(發送M1,確認M1;發送M2,確認M2;發送M3,M3丟失;發送M4,確認M2;發送M5,確認M2;發送M6,確認M2;)收到3個重復的確認,立即重傳。
快恢復:ssthresh=cwnd/2;cwnd=ssthren(丟失了3個報文段,擁塞窗口可以不置為1)
綜合
TCP的三次握手過程
所謂三次握手,是指建立一個TCP連接時,需要客戶端和服務器總共發送 3個包
三次握手的目的是: 客戶端連接服務器到指定的端口,建立TCP連接.并同步連接雙方的序列號和確認號并交換TCP窗口大小信息.
在Socket編程中,客戶端執行connect()時,將觸發三次握手
首先我們需要知道以下四個概念:
序列號seq: 占4個字節,用來標記數據段的順序,就是這個報文段中的第一個字節的數據編號
確認號ack: 占4個字節,期待收到對方下一個報文段的第一個數據字節的序號
同步SYN: 連接建立時用于同步序號。
? 當SYN=1,ACK=0時表示:這是一個連接請求報文段。
? 若同意連接,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連接請求,或連接接受報文。
? SYN這個標志位只有在TCP建產連接時才會被置1,握手完成后SYN標志位被置0。
確認ACK: 占1位,僅當ACK=1時,確認號字段才有效。ACK=0時,確認號無效
- 第一次握手: 建立連接時,客戶端A發送SYN包(seq = x)到服務器B,并進入SYN_SEND狀態,等待服務器B確認
- 第二次握手: 服務器B收到服務器發送的SYN包.必須確認客戶端A的SYN(ack = x + 1,seq = y),同時自己也會發送一個SYN包,即SYN + ACK包,此時服務器進入SYN_RECV狀態
- 第三次握手: 客戶端A收到服務器B的SYN包 + ACK包,向服務器B發送確認包ACK,此時無需將SYN標識置為1(seq = x + 1,ack = y + 1),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態
- 完成三次握手以后,客戶端和服務器端即可以開始進行傳送數據
能否變為二次握手
滯留在網絡中的請求到達服務器,會導致服務器給客服發送請求,并進入已建立連接狀態;
服務器不理睬該請求,仍為關閉狀態
服務器處于已建立連接狀態會等待客戶端的請求,造成服務器資源浪費
accept connect listen對應三次握手什么階段
客戶端調用connect的時候,就是發一個syn包
服務端accept的時候,實際上是從內核的accept隊列里面取一個連接,如果這個隊列為空,則進程阻塞(阻塞模式下)。如果accept返回則說明成功取到一個連接,返回到應用層。
大致的過程是客戶端發一個syn之后,服務端將這個連接放入到backlog隊列,在收到客戶端的ack之后將這個請求移到accept隊列。所以accept一定是發生在三次握手之后,connect只是發一個syn而已
Accept根本不參與三次握手,服務器只要Listen,客戶端connect是與服務器內核握手,connect完成之后,服務器都不需要寫Accept,客戶端就已經可以發送數據了,你完全可以讓這批數據在服務器里躺一年之后,再Accept也可以
tcp三次握手的過程,accept發生在三次握手哪個階段?
第一次握手:客戶端發送syn包(syn=j)到服務器。
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個ASK包(ask=k)。
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1)。
三次握手完成后,客戶端和服務器就建立了tcp連接。這時可以調用accept函數獲得此連接
TCP的四次揮手過程
TCP通信雙方都可以釋放連接
TCP的連接的拆除需要發送四個包,因此稱為四次揮手。客戶端或服務器均可主動發起揮手動作,在socket編程中,任何一方執行close()操作即可產生揮手操作。
TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務后就能發送一個FIN來終止這個方向的連接。收到一個 FIN只意味著這一方向上沒有數據流動,一個TCP連接在收到一個FIN后仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
- (1) TCP客戶端發送一個FIN,用來關閉客戶端到服務器端的數據傳送(即告訴服務器我要和你斷開連接)
- (2) 服務器收到這個FIN,它會發送一個ACK,確認序號為收到的序號加1.和SYN一樣,一個FIN將占用一個序號(即告訴客戶端你不能給我發了,但是此時服務器端還是可以給客戶端發送信息的)
- (3) 服務器端關閉與客戶端的連接,發送一個FIN包給客戶端(此時服務器端也告訴客戶端我也要和你斷開連接)
- (4) 客戶端發送ACK報文確認,并將確認序號設置為收到的序號加1(客戶端同意了服務器端的請求,此時確認以后,服務器端也不能給服務器端發送數據了)
以第一次揮手為例各個標志位的含義:
FIN:表明這是一個TCP連接釋放報文段
ACK:對之前接收的報文段進行確認
ack:服務端傳送過來的字節的最后一個字節序號+1
seq:客戶端發送字節的最后一個字節序號+1
客戶端時間等待狀態是否有必要?
如果客戶端最后一次揮手發送過程中丟失,會導致服務器一直重傳TCP連接釋放,無法進入關閉狀態
添加等待狀態可以確保服務器收到最后一個TCP確認報文段而進入關閉狀態,另外,客戶端在發完最后一個TCP確認報文段后再經過2MLS,可以使本次連接持續時間內所產生的所有報文段都從網絡中消失,使下一個TCP連接中不會出現舊連接中的報文段。
如果客戶端出現故障,客戶端如何發現?
TCP服務器每次收到一次TCP客戶端進程的數據,就重新設置并啟動保活計時器(2h),若保活周期內未收到TCP客戶端的數據,TCP服務器就像TCP客戶端發送探測報文段,以后每75s發送一次,若一臉發送10個仍沒收到TCP客戶端的響應,TCP服務端就認為TCP客戶端出現了故障,接著就關閉這個鏈接。
四次揮手timewait
當客戶端最后一次發送消息時并沒有直接進入close狀態而是進入TIME_WAIT狀態,這是因為TCP是面向連接的協議,每一次發送都需要確認對方是否收到消息。客戶端最后一次發送消息時可能會由于網絡等其他原因導致服務器收不到消息,服務器就會選擇從新給客戶端發送一個FIN的包,如果客戶端處于關閉狀態將永遠也收不到服務器發給它的消息了。至于這個時間要等多久才能確認對方收到了消息呢。
報文在網絡中有一個最大生存時間MSL超過這個時間就會被丟棄并通知源主機。
TIME_WAIT 要等待 2MSL 才會進入 CLOSED 狀態。
ACK包到達服務器需要MSL時間,服務器重傳 FIN 包也需要MSL時間,2MSL 是數據包往返的最大時間,通常為2min,如果2MSL后還未收到服務器重傳的FIN 包,就說明服務器已經收到了ACK包,此時由TIME_WAIT狀態轉變為CLOSED狀態.
Jetbrains全家桶1年46,售后保障穩定
tcp keepalive實現原理
TCP的keepalive的來源
雙方建立交互的連接,但是并不是一直存在數據交互,有些連接會在數據交互完畢后,主動釋放連接,而有些不會,那么在長時間無數據交互的時間段內,交互雙方都有可能出現掉電、死機、異常重啟等各種意外,當這些意外發生之后,這些TCP連接并未來得及正常釋放,那么,連接的另一方并不知道對端的情況,它會一直維護這個連接,長時間的積累會導致非常多的半打開連接,造成端系統資源的消耗和浪費,為了解決這個問題,在傳輸層可以利用TCP的保活報文來實現。
TCP的keepalive的作用
利用保活探測功能,可以探知這種對端的意外情況,從而保證在意外發生時,可以釋放半打開的TCP連接。
tcp三次握手四次揮手過程及各個狀態
三次握手狀態:
(1) 第一次握手[同步已發送狀態,SYN-SENT]
(2) 第二次握手[同步收到狀態,SYN-REVD]
(3) 第三次握手[已建立連接狀態,ESTABLISHED]
四次揮手狀態:
(1) FIN-WAIT-1(終止等待1)狀態[客戶端]
(2) CLOSE-WAIT(關閉等待)狀態[服務端]
(3) FIN-WAIT-2(終止等待2)狀態[客戶端]
(4) LAST-ACK(最后確認)狀態[服務端]
(5) TIME-WAIT(時間等待)狀態[客戶端] 這個是考點!!!
(6) CLOSED狀態[服務端]
為什么三次為什么四次
TCP連接為什么是三次的問題?
TCP協議為了實現可靠傳輸,通信雙方需要判斷自己已經發送的數據包是否都被接收方收到, 如果沒收到, 就需要重發。 為了實現這個需求,很自然地就會引出序號(sequence number) 和 確認號(acknowledgement number) 的使用。
故為了可靠傳輸,發送方和接收方始終需要同步SYN序號,不僅客戶端向服務器端發送SYN包請求連接,并且服務器端發送ACK包(確認包)同意請求,也需要向客戶端發送SYN包請求連接,并得到客戶端的ACK包(確認包),只有雙方都發送并接收響應,才算連接成功!
TCP斷開連接為什么是四次的問題?
TCP協議是一種面向連接的、可靠的、基于字節流的運輸層通信協議。
TCP是全雙工模式,這就意味著,當客戶端發出
FIN報文段給服務器端時,只是表示客戶端已經沒有數據要發送了,即表示它的數據已經全部發送完畢了;但是,這個時候客戶端還是可以接受來自服務器端的數據的;當服務器端返回ACK報文段時,表示它已經知道了客戶端沒有數據發送了,但是服務器還是可以發送數據到客戶端的;當服務器也發送了FIN報文段時,這個時候就表示客戶端也沒有數據要發送了,就等于告訴我也沒有數據要發送了,之后等到客戶端返回ACK報文段的時候,彼此才會真正的,愉快的中斷這次TCP連接。
SYN攻擊是什么?
我們說在建立TCP連接的過程中,服務器發送SYN-ACK包之后,收到客戶端的ACK包之前的狀態叫做半連接狀態,此時服務器處于SYN-RECV狀態,當服務器收到ACK包后,稱為ESTABLISHED狀態
**SYN攻擊指的是攻擊客戶端,在短時間內偽造出大量的不存在的IP地址,向服務器端進行發送SYN包,此時服務器回復確認包(ACK),并等待客戶端的確認,由于很大的IP地址是不存在的,導致服務器需要不斷地進行重復發送直至超時!**而這些偽造的SYN包將長時間占用未連接隊列,正常的SYN請求被丟棄,目標系統運行緩慢,嚴重者將引起網絡堵塞甚至系統癱瘓.
解決方案:
在Linux系統下可以如下命令檢測是否被Syn攻擊
netstat -n -p TCP | grep SYN_RECV
一般較新的TCP/IP協議棧都對這一過程進行修正來防范Syn攻擊,修改tcp協議實現。主要方法有SynAttackProtect保護機制、SYN cookies技術、增加最大半連接和縮短超時時間等等,但是都不能完全地防范SYN攻擊.
TCP建立連接過程中,第三次握手seq=1000,ack=2000.問第二次握手seq和ack分別為多少?
首先我們需要知道幾個概念:
- 序列號seq: 占4個字節,用來標記數據段的順序,就是這個報文段中的第一個字節的數據編號
- 確認號ack: 占4個字節,期待收到對方下一個報文段的第一個數據字節的序號
- 同步SYN: 連接建立時用于同步序號。當SYN=1,ACK=0時表示:這是一個連接請求報文段。若同意連接,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連接請求,或連接接受報文。SYN這個標志位只有在TCP建產連接時才會被置1,握手完成后SYN標志位被置0。
- 確認ACK: 占1位,僅當ACK=1時,確認號字段才有效。ACK=0時,確認號無效
第一次握手:建立連接時,客戶端發送SYN包(seq=x)到服務器,并進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
第二次握手:服務器收到SYN包,將SYN和ACK標識都置為1,然后設置(seq=y,ack=x+1),向客戶端發送一個SYN+ACK包,此時服務器進入SYN_RECV狀態.
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包,將ACK置為1,S此時無需SYN,(seq=x+1,ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。
所以 :
這題中,第三次的seq = x + 1 = 2000,ack = y + 1 = 1000,說明第二次的seq = y = 1999,ack = x + 1 = 1000
tcp粘包
什么是TCP粘包?
TCP粘包就是指發送方發送的若干包數據到達接收方時粘成了一包,從接收緩沖區來看,后一包數據的頭緊接著前一包數據的尾,出現粘包的原因是多方面的,可能是來自發送方,也可能是來自接收方。
粘包產生的原因
(1) 發送方原因
TCP默認使用Nagle算法(主要作用:減少網絡中報文段的數量),而Nagle算法主要做兩件事:
- 只有上一個分組得到確認,才會發送下一個分組
- 收集多個小分組,在一個確認到來時一起發送
Nagle算法造成了發送方可能會出現粘包問題
(2) 接收方原因
TCP接收到數據包時,并不會馬上交到應用層進行處理,或者說應用層并不會立即處理。實際上,TCP將接收到的數據包保存在接收緩存里,然后應用程序主動從緩存讀取收到的分組。這樣一來,如果TCP接收數據包到緩存的速度大于應用程序從緩存中讀取數據包的速度,多個包就會被緩存,應用程序就有可能讀取到多個首尾相接粘到一起的包。
如何解決粘包問題
(1)發送方
對于發送方造成的粘包問題,可以通過關閉Nagle算法來解決,使用TCP_NODELAY選項來關閉算法。
(2)接收方
接收方沒有辦法來處理粘包現象,只能將問題交給應用層來處理。
(2)應用層
應用層的解決辦法簡單可行,不僅能解決接收方的粘包問題,還可以解決發送方的粘包問題。
解決辦法:循環處理,應用程序從接收緩存中讀取分組時,讀完一條數據,就應該循環讀取下一條數據,直到所有數據都被處理完成,但是如何判斷每條數據的長度呢?
- 格式化數據:每條數據有固定的格式(開始符,結束符),這種方法簡單易行,但是選擇開始符和結束符時一定要確保每條數據的內部不包含開始符和結束符。
- 發送長度:發送每條數據時,將數據的長度一并發送,例如規定數據的前4位是數據的長度,應用層在處理時可以根據長度來判斷每個分組的開始和結束位置。
UDP會不會產生粘包問題呢?
TCP為了保證可靠傳輸并減少額外的開銷(每次發包都要驗證),采用了基于流的傳輸,基于流的傳輸不認為消息是一條一條的,是無保護消息邊界的(保護消息邊界:指傳輸協議把數據當做一條獨立的消息在網上傳輸,接收端一次只能接受一條獨立的消息)。
UDP則是面向消息傳輸的,是有保護消息邊界的,接收方一次只接受一條獨立的信息,所以不存在粘包問題。
舉個例子:有三個數據包,大小分別為2k、4k、6k,如果采用UDP發送的話,不管接受方的接收緩存有多大,我們必須要進行至少三次以上的發送才能把數據包發送完,但是使用TCP協議發送的話,我們只需要接受方的接收緩存有12k的大小,就可以一次把這3個數據包全部發送完畢。
XSS(Cross Site Scripting) 跨域腳本攻擊
攻擊原理 :
XSS攻擊的核心原理是:不需要你做任何的登錄認證,它會通過合法的操作(比如在url中輸入、在評論框中輸入),向你的頁面注入腳本(可能是js、hmtl代碼塊等)
最后導致的結果可能是:盜用Cookie破壞頁面的正常結構,插入廣告等惡意內容D-doss攻擊
如何防御XSS攻擊?
- 編碼 :把js代碼轉義成字符串
- 過濾 :移除用戶輸入的和事件相關的屬性。如onerror可以自動觸發攻擊,還有onclick等。(總而言是,過濾掉一些不安全的內容)移除用戶輸入的Style節點、Script節點、Iframe節點。(尤其是Script節點,它可是支持跨域的呀,一定要移除)。
- 校正:避免直接對HTML Entity進行解碼。使用DOM Parse轉換,校正不配對的DOM標簽。DOM Parse這個概念,它的作用是把文本解析成DOM結構。比較常用的做法是,通過第一步的編碼轉成文本,然后第三步轉成DOM對象,然后經過第二步的過濾。
CSRF(Cross-Site Request Forgery) 跨站請求偽造
攻擊原理 :
如何防御CSRF攻擊?
- Token 驗證:(用的最多)
(1)服務器發送給客戶端一個token;
(2)客戶端提交的表單中帶著這個token。
(3)如果這個 token 不合法,那么服務器拒絕這個請求。
-
隱藏令牌:把 token 隱藏在 http 的 head頭中。方法二和方法一有點像,本質上沒有太大區別,只是使用方式上有區別。
-
Referer 驗證:Referer 指的是頁面請求來源。意思是,只接受本站的請求,服務器才做響應;如果不是,就攔截。
XSS和CSRF區別
- csrf中B利用C獲取A的信任,得到cookie,再破壞A;XSS:不需要登錄。
- csrf利用A本身的漏洞;xss注入js代碼,篡改a的內容。
sql注入和防范(美團)
什么是SQL注入?
簡單的理解,SQL注入就是我們將SQL命令插入到WEB表單或者是頁面請求url的請求字符串,最終達到欺騙服務器的執行惡意的SQL命令的目的。
總結來說,SQL注入就是指通過構建特殊的輸入作為參數傳入WEB應用程序,而這些輸入大多數情況下都是SQL語法中的一些組合,通過執行SQL語句進而執行了攻擊者攜帶的操作。
導致SQL注入的主要原因是沒有細致地過濾用戶輸入的數據,致使非法數據侵入系統
SQL注入的典型案例 – 用戶登錄問題
案例 : 我們在用戶登錄的時候,需要輸入用戶名和密碼進行登錄,此時如果我們沒有防范SQL注入,在用戶登錄信息中輸入以下信息,將會免密登錄,這導致對我們的系統造成了極大的不安全性!
用戶名 :or 1 = 1 –
密碼 :
首先我們來說一下后臺驗證用戶名和密碼的SQL語句為 :
select * form user_table where username = 'username' and password = 'password';
此時我們輸入上面的用戶名和密碼以后 :
select * form user_table where username = '' or 1 = 1 -- and password = 'password';
這里就會出現問題了:
我們說在SQL語句中, – 表示注釋,此時 1 = 1為true,前面用 ‘or‘進行連接,則該條件一定成立,故我們登陸成功
此時如果我們注入的語句不是登陸,而是刪除數據表結構,那如果沒有對SQ注入進行防范,這樣的危害是及其大的!!!
SQL防范
1. 對于普通用戶和系統管理員用戶的權限進行嚴格的劃分
如果是對數據庫的一些刪除,建立等操作,我們需要系統管理用戶才能進行操作,即我們在設計數據庫時,把系統管理員的用戶與普通用戶區分開來。
2.強迫使用參數化語句
如果在編寫SQL語句的時候,用戶輸入的變量不是直接嵌入到SQL語句。而是通過參數來傳遞這個變量的話,那么就可以有效的防治SQL注入式攻擊
3. 加強對用戶輸入的驗證
加強對用戶輸入內容的檢查與驗證
4. 使用預編譯(PreStatement)
PreparedStatement會對SQL進行了預編譯,在第一次執行SQL前數據庫會進行分析、編譯和優化,同時執行計劃同樣會被緩存起來,它允許數據庫做參數化查詢。在使用參數化查詢的情況下,數據庫不會將參數的內容視為SQL執行的一部分,而是作為一個字段的屬性值來處理,這樣就算參數中包含破環性語句(or ‘1=1’),也只能作為參數,而不能作為SQL語句內容,故不會被執行。
大部分的SQL框架,例如: Hibernate,Mybatis,JPA等都支持預編譯,故能夠防范SQL注入問題
HTTP/TCP/IP
1. HTTP(HyperText Transport Protocol)
HTTP是超文本傳輸協議的縮寫,它是用來傳送WWW方式的數據,按層次劃分,它屬于應用層.HTTP協議采用了請求/響應模型.
2. TCP(Transmission Control Protocol )
TCP是指傳輸控制協議,是一種面向連接的,可靠的,基于字節流的傳輸層通信協議. 其中用戶數據報協議(UDP)也是傳輸層另一種重要的傳輸協議(后面會進行比較) ,他屬于傳輸層。
3. IP(Internet Protocol)
IP指的是網絡之間互連的協議,也就是為計算機網絡相互連接進行通信而設計的協議,它屬于網絡層.
如今的IP網絡使用32位地址,以點分十進制表示,如192.168.0.1
地址格式為:IP地址 = 網絡地址+主機地址 或 IP地址 = 網絡地址 + 子網地址 + 主機地址
HTTP的報文結構
一個HTTP請求報文由四個部分組成 : 請求行、請求頭部、空行和請求數據(請求體)
一個HTTP響應報文也由四個部分組成:狀態行、響應頭部,空行和響應體
HTTP與HTTPS的區別
HTTP協議傳輸的數據都是未加密的,也就是明文的,因此使用HTTP協議傳輸隱私信息非常不安全,為了保證這些隱私數據能加密傳輸,于是網景公司設計了SSL(Secure Sockets Layer)協議用于對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。
簡單來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比HTTP協議安全
總結兩者主要的區別如下所示:
1、https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
2、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
4、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
HTTP1.0 和 HTTP1.1之間的區別
1. 長連接(Persistent Connection)
HTTP1.1支持長連接和請求的流水線處理,在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲,在HTTP1.1中默認開啟長連接keep-alive,一定程度上彌補了HTTP1.0每次請求都要創建連接的缺點。HTTP1.0需要使用keep-alive參數來告知服務器端要建立一個長連接。
2. 節約帶寬
HTTP1.0中存在一些浪費帶寬的現象,例如客戶端只是需要某個對象的一部分,而服務器卻將整個對象送過來了,并且不支持斷點續傳功能。HTTP1.1支持只發送header信息(不帶任何body信息),如果服務器認為客戶端有權限請求服務器,則返回100,客戶端接收到100才開始把請求body發送到服務器;如果返回401,客戶端就可以不用發送請求body了節約了帶寬。
3. HOST域
在HTTP1.0中認為每臺服務器都綁定一個唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機名(hostname),HTTP1.0沒有host域。隨著虛擬主機技術的發展,在一臺物理服務器上可以存在多個虛擬主機(Multi-homed Web Servers),并且它們共享一個IP地址。HTTP1.1的請求消息和響應消息都支持host域,且請求消息中如果沒有host域會報告一個錯誤(400 Bad Request)。
4. 緩存處理
在HTTP1.0中主要使用header里的If-Modified-Since,Expires來做為緩存判斷的標準,HTTP1.1則引入了更多的緩存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的緩存頭來控制緩存策略。
5. 錯誤通知的管理
在HTTP1.1中新增了24個錯誤狀態響應碼,如409(Conflict)表示請求的資源與資源的當前狀態發生沖突;410(Gone)表示服務器上的某個資源被永久性的刪除。
https為什么要采用對稱和非對稱加密結合的方式
雖然說非對稱加密安全,但是由于和對稱加密比較來說,速度較慢(指的是加密和解密的速度而言),故我們https采用了將對稱加密和非對稱加密結合的方式,即我們將對稱加密的秘鑰使用非對稱加密的公鑰進行加密,然后發送出去,接收方使用非對稱的私鑰進行解密得到對稱加密的秘鑰,此時雙方就可以使用對稱加密的秘鑰進行通信溝通了,這樣既保證了安全性,又增加了通信的速度,即加密和解密的速度.
對稱加密和非對稱加密的區別
對稱加密:快速簡單,加密和解密都使用同樣的秘鑰。
非對稱加密:安全,使用一對密鑰,公鑰/私鑰。私鑰由一方安全保管,公鑰可以發給任何請求他的人,發送請求時通過公鑰對消息進行加密,只有擁有私鑰的人才能對你的消息進行解密,安全性大大提高。
SSL加密過程:
1.客戶端向服務端發送請求
2.服務端返回給客戶端公鑰
3.客戶端使用公鑰對信息加密后在想服務端發送請求
4.服務端通過私鑰對信息解密
公鑰私鑰加密原理
RSA加密算法:
一種公鑰密碼體制,公鑰公開,私鑰保密,它的加密解密算法是公開的。 RSA的這一對公鑰、私鑰都可以用來加密和解密,并且一方加密的內容可以由并且只能由對方進行解密。
- 對稱加密與非對稱加密結合
- 判別公鑰是否屬于客戶端
-
數字簽名
為了防止證書頒發過程中被人修改,出現了數字簽名。
CA機構將證書內容用hash算法生成hash字符串1,并用CA私鑰加密發送給服務端
服務端用CA公鑰解密得到hash字符串1,同時也將證書內容用hash算法生成hash字符串2,如果hash字符串1與hash字符串2相同,說明證書沒被修改過
HTTP1.1 和 HTTP2.0之間的區別
1.多路復用
HTTP2.0使用了多路復用的技術,做到**同一個連接并發處理多個請求,而且并發請求的數量比HTTP1.1大了好幾個數量級。**HTTP1.1也可以多建立幾個TCP連接,來支持處理更多并發的請求,但是創建TCP連接本身也是有開銷的。
2. 頭部數據壓縮
HTTP1.1不支持header數據的壓縮,HTTP2.0使用HPACK算法對header的數據進行壓縮,這樣數據體積小了,在網絡上傳輸就會更快。
3. 服務器推送
服務端推送是一種在客戶端請求之前發送數據的機制。網頁使用了許多資源:HTML、樣式表、腳本、圖片等等。在HTTP1.1中這些資源每一個都必須明確地請求。這是一個很慢的過程。瀏覽器從獲取HTML開始,然后在它解析和評估頁面的時候,增量地獲取更多的資源。因為服務器必須等待瀏覽器做每一個請求,網絡經常是空閑的和未充分使用的.
為了改善延遲,HTTP2.0引入了server push,它允許服務端推送資源給瀏覽器,在瀏覽器明確地請求之前,免得客戶端再次創建連接發送請求到服務器端獲取。這樣客戶端可以直接從本地加載這些資源,不用再通過網絡。
下面這張圖是由TMX總結 :
HTTP0.9 /HTTP1.0/HTTP1.1 /HTTP2.0/HTTP3.0
超文本傳輸協議,基于TCP/IP通信協議來傳遞數據
1.HTTP0.9
HTTP/0.9是第一個版本的HTTP協議,已過時。它的組成極其簡單,只允許客戶端發送GET這一種請求,且不支持請求頭。由于沒有協議頭,造成了HTTP/0.9協議只支持一種內容,即純文本。
HTTP/0.9具有典型的無狀態性,每個事務獨立進行處理,事務結束時就釋放這個連接。由此可見,HTTP協議的無狀態特點在其第一個版本0.9中已經成型。一次HTTP/0.9的傳輸首先要建立一個由客戶端到Web服務器的TCP連接,由客戶端發起一個請求,然后由Web服務器返回頁面內容,然后連接會關閉。如果請求的頁面不存在,也不會返回任何錯誤碼。
2.HTTP1.0
相對于HTTP/0.9增加了如下主要特性:
-
開始支持客戶端通過POST方法向Web服務器提交數據,支持GET、HEAD、POST方法
-
請求與響應支持頭域
-
響應對象不只限于超文本
-
響應對象以一個響應狀態行開始
-
支持長連接(但默認還是使用短連接),緩存機制,以及身份認證
3.HTTP1.1
是目前使用最廣泛的協議版本。相對于HTTP/1.0新增了以下內容:
3.1 默認為長連接
HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理,在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲,在HTTP1.1中默認開啟Connection:keep-alive,一定程度上彌補了HTTP1.0每次請求都要創建連接的缺點。
3.2 寬帶優化
提供了范圍請求功能,HTTP1.0中,存在一些浪費帶寬的現象,例如客戶端只是需要某個對象的一部分,而服務器卻將整個對象送過來了,并且不支持斷點續傳功能,HTTP1.1則在請求頭引入了range頭域,它允許只請求資源的某個部分,即返回碼是206(Partial Content),這樣就方便了開發者自由的選擇以便于充分利用帶寬和連接。這是支持文件斷點續傳的基礎。
3.3 提供了HOST域
提供了虛擬主機的功能,在HTTP1.0中認為每臺服務器都綁定一個唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機名(hostname)。但隨著虛擬主機技術的發展,在一臺物理服務器上可以存在多個虛擬主機(Multi-homed Web Servers),并且它們共享一個IP地址。HTTP1.1的請求消息和響應消息都應支持Host頭域,且請求消息中如果沒有Host頭域會報告一個錯誤(400 Bad Request)。
3.4 多了一些緩存處理字段
HTTP/1.1在1.0的基礎上加入了一些cache的新特性,引入了實體標簽,一般被稱為e-tags,新增更為強大的Cache-Control頭。
3.5 錯誤通知的管理
在HTTP1.1中新增了24個錯誤狀態響應碼,如409(Conflict)表示請求的資源與資源的當前狀態發生沖突;410(Gone)表示服務器上的某個資源被永久性的刪除。
4.HTTP2.0
相對于HTTP/1.1新增了以下內容:
4.1 二進制分幀
HTTP 2.0 的所有幀都采用二進制編碼
幀:客戶端與服務器通過交換幀來通信,幀是基于這個新協議通信的最小單位。
消息:是指邏輯上的 HTTP 消息,比如請求、響應等,由一或多個幀組成。
流:流是連接中的一個虛擬信道,可以承載雙向的消息;每個流都有一個唯一的整數標識符(1、2 … N);
4.2 多路復用
多路復用允許同時通過單一的HTTP/2.0 連接發起多重的請求-響應消息。有了新的分幀機制后,HTTP/2.0不再依賴多個TCP 連接去處理更多并發的請求。每個數據流都拆分成很多互不依賴的幀,而這些幀可以交錯(亂序發送),還可以分優先級。最后再在另一端根據每個幀首部的流標識符把它們重新組合起來。HTTP 2.0 連接都是持久化的,而且客戶端與服務器之間也只需要一個連接(每個域名一個連接)即可。
4.3 頭部壓縮
HTTP/1.1 的首部帶有大量信息,而且每次都要重復發送。HTTP/2.0 要求通訊雙方各自緩存一份首部字段表,從而避免了重復傳輸。
4.4 請求優先級
瀏覽器可以在發現資源時立即分派請求,指定每個流的優先級,**讓服務器決定最優的響應次序。**這樣請求就不必排隊了,既節省了時間,也最大限度地利用了每個連接。
4.5 服務端推送Server Push
把客戶端所需要的資源伴隨著index.html一起發送到客戶端,省去了客戶端重復請求的步驟。正因為沒有發起請求,建立連接等操作,所以靜態資源通過服務端推送的方式可以極大地提升速度。
5.http3.0(QUIC)
快速UDP互聯網連接
2個主要特征:
5.1 解決阻塞問題
基于TCP的HTTP/2,盡管從邏輯上來說,不同的流之間相互獨立,不會相互影響,但在實際傳輸方面,數據還是要一幀一幀的發送和接收**,一旦某一個流的數據有丟包,則同樣會阻塞在它之后傳輸的流數據傳輸**。而基于UDP的QUIC協議則可以更為徹底地解決這樣的問題,讓不同的流之間真正的實現相互獨立傳輸,互不干擾。
5.2切換網絡時的連接保持
當前移動端的應用環境,用戶的網絡可能會經常切換,比如從辦公室或家里出門,WiFi斷開,網絡切換為3G或4G。基于TCP的協議,由于切換網絡之后,IP會改變,因而之前的連接不可能繼續保持。而基于UDP的QUIC協議,則可以內建與TCP中不同的連接標識方法,從而在網絡完成切換之后,恢復之前與服務器的連接。
HTTP的請求
- OPTIONS:返回服務器針對特定資源所支持的HTTP請求方法。也可以利用向Web服務器發送’*’的請求來測試服務器的功能性。
- HEAD:向服務器索要與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應消息頭中的元信息。
- GET:向特定的資源發出請求。
- POST:向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的創建和/或已有資源的修改。
- PUT:向指定資源位置上傳其最新內容。
- DELETE:請求服務器刪除Request-URI所標識的資源。
- TRACE:回顯服務器收到的請求,主要用于測試或診斷。
- CONNECT:HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。
get /post請求的區別(字節)
-
get參數包含在URL中,長度有限制,會保留在歷史記錄里,post通過request body傳遞參數,長度沒有限制,不會保留
-
回退時,get請求會從緩存中讀取數據,而post會重新發送請求
-
get請求的URL地址可以被收藏,post不可以
-
get請求只能進行url編碼,post支持多種編碼方式
GET和POST本質上沒有區別
HTTP是基于TCP/IP的關于數據如何在萬維網中如何通信的協議。HTTP的底層是TCP/IP。所以GET和POST的底層也是TCP/IP,也就是說,GET/POST都是TCP鏈接。不同的瀏覽器(發起http請求)和服務器(接受http請求)就是不同的運輸公司,他們對get/post請求的數據處理不同。
GET和POST還有一個重大區別
GET產生一個TCP數據包;POST產生兩個TCP數據包。
對于GET方式的請求,瀏覽器會把http header和data一并發送出去,服務器響應200(返回數據);
而對于POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok(返回數據)。
HTTP常見的狀態碼
| 狀態碼 | 類別 | 原因短語 |
|---|---|---|
| 1XX | Informational(信息性狀態碼,服務器給客戶端的信息) | 接收的請求正在處理 |
| 2XX | Success(成功狀態碼) | 請求正常處理完畢 |
| 3XX | Redirection(重定向狀態碼) | 需要進行附加操作以完成請求 |
| 4XX | Client Error(客戶端錯誤狀態碼) | 服務器無法進行處理請求 |
| 5XX | Server Error(服務器錯誤狀態碼) | 服務器處理請求出錯 |
| 狀態碼 | 描述 |
|---|---|
| 200 OK | 請求已正常處理 |
| 301 Moved Permanently | 永久性重定向 : 請求的資源已經被分配了新的URI,以后應使用資源現在所指的URI |
| 302 Found | 臨時性重定向 : 和301相似,但302代表的資源不是永久性移動,只是臨時性性質的。換句話說,已移動的資源對應的URI將來還有可能發生改變 |
| 303 See Other | 303狀態碼和302狀態碼有著相同的功能,但303狀態碼明確表示客戶端應當采用GET方法獲取資源,這點與302狀態碼有區別 |
| 304 Not Modified | 該狀態碼表示客戶端發送附帶條件的請求時(采用GET方法的請求報文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部)服務端允許請求訪問資源,但因發生請求未滿足條件的情況后,直接返回304.。 |
| 400 Bad Request | 服務器端無法理解客戶端發送的請求,請求報文中可能存在語法錯誤((前端提交到后臺的數據應該是json字符串類型,但是前端沒有將對象JSON.stringify轉化成字符串)) |
| 401 Unauthorized | 該狀態碼表示發送的請求需要有通過HTTP認證(BASIC認證,DIGEST認證)的認證信息 |
| 403 Forbidden | 不允許訪問那個資源。該狀態碼表明對請求資源的訪問被服務器拒絕了。(權限,未授權IP等) |
| 404 Not Found | 服務器上沒有請求的資源。路徑錯誤等 |
| 500 Internal Server Error | 該狀態碼表明服務器端在執行請求時發生了錯誤。也有可能是web應用存在bug或某些臨時故障 |
| 503 Service Unavailable | 服務器暫時處于超負載或正在停機維護,現在無法處理請求 |
| 502 | 作為網關或者代理工作的服務器嘗試執行請求時,從上游服務器接收到無效的響應。 |
| 504 | 作為網關或者代理工作的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。 |
HTTP的only(美團優選)
如果在cookie中設置了HttpOnly,那么通過程序(js腳本)將無法讀取到cookie信息,這樣能有效防止XSS攻擊
HTTP的Referer
表示來源,正確英語拼法是Referrer,為了向后兼容,將錯就錯
在www.google.com里有一個
www.baidu.com鏈接,那么點擊這個www.baidu.com,它的header信息里就有:Referer=http://www.google.com,可以利用這個來防止盜鏈了,比如我只允許我自己的網站訪問我自己的圖片服務器,那我的域名是www.google.com,那么圖片服務器每次取到Referer來判斷一下是不是我自己的域名www.google.com,如果是就繼續訪問,不是就攔截。直接在地址欄中輸入URL的地址是不會包含referer字段的,因為他不是藏一個地方鏈接過去的
允許 Referer 為空,意味著你允許比如瀏覽器直接訪問,就是空
請求轉發(Redirect)和重定向(Forward)之間的區別
- 地址欄信息 : 重定向會顯示轉向以后的地址,而請求轉發不會顯示轉向的地址
- 請求次數 : 重定向至少提交了兩次請求
- 數據 : 請求轉發對request對象的信息不會丟失,因此可以在多個頁面交互過程中實現請求數據的共享; 而重定向之前request域信息將丟失
- 原理 : 請求轉發是在服務器內部控制權的轉移,是由服務器區請求,客戶端并不知道是怎樣轉移的,因此客戶端的地址不會顯示出轉向的地址; 重定向則是服務器告訴客戶端要轉向哪個地址,客戶端再自己去請求轉向的地址,因此會顯示轉向后的地址,也可以理解為瀏覽器至少進行了兩次的訪問請求
- 速度 : 請求轉發的速度遠遠快于重定向
請求轉發和重定向的應用場景
- 1、重定向的速度比轉發慢,因為瀏覽器還得發出一個新的請求,如果在使用轉發和重定向都無所謂的時候建議使用轉發。
- 2、因為轉發只能訪問當前WEB的應用程序,所以不同WEB應用程序之間的訪問,特別是要訪問到另外一個WEB站點上的資源的情況,這個時候就只能使用重定向了。
RPC和HTTP的區別
RPC(Remote Produce Call) 遠程過程調用
是一個計算機通信協議,該協議允許運行于一臺計算機的程序調用另一臺計算機的子程序,而程序員無需額外地為這個交互作用編程.它是建立在Socket之上
RPC實現遠程調用的策略:
(1) 采用何種網絡通訊協議?
比較流行的RPC框架,采用的都是TCP作為底層傳輸協議
(2)數據傳輸的格式是怎么樣的?
不同于HTTP,RPC遠程過程調用需要讓調用者和被調用者采用相同的數據傳輸格式,就好比兩個人使用同一種語言進行交流溝通一樣.
下面是RPC的調用流程圖:
HTTP(HyperText Transport Protocol)
HTTP稱為超文本傳輸協議,是一種應用層的協議,規定了網絡傳輸的請求格式、響應格式、資源定位和操作的方式等。但是底層采用什么網絡傳輸協議,并沒有規定,不過現在都是采用TCP協議作為底層傳輸協議.
客戶端通過HTTP向服務器端發送請求,并接受響應的流程:
比較RPC和HTTP
- RPC通過Thrift二進制進行傳輸,而HTTP的json序列化更消耗性能 (即在序列化和反序列化方式上的區別)
- RPC自帶負載均衡,而HTTP需要自己設置負載均衡
- RPC可以自定義TCP協議,報文相對來說較小
- RPC是一種API,HTTP是一種無狀態的網絡協議。RPC可以基于HTTP協議實現,也可以直接在TCP協議上實現
- RPC主要是用在大型網站里面,因為大型網站里面系統繁多,業務線復雜,而且效率優勢非常重要的一塊,這個時候RPC的優勢就比較明顯了.HTTP主要是用在中小型企業里面,業務線沒那么繁多的情況下
- HTTP需要事先通知,修改Nginx/HAProxy配置。RPC能做到自動通知,不影響上游
常用的RPC框架: webservie(cxf)、dubbo
HTTP客戶端工具: HTTPClient
Socket是什么?
網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個Socket。建立網絡通信連接至少要一對端口號(Socket)。Socket本質是編程接口(API).
當然我們也可以理解為: Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口后面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。
Socket中的time-wait狀態多,如何解決
在高并發短連接的server端,當server處理完client的請求后立刻close socket此時會出現time_wait狀態,然后如果client再并發2000個連接,此時部分連接就連接不上了,用linger強制關閉可以解決此問題,但是linger會導致數據丟失,linger值為0時是強制關閉,無論并發多少多能正常連接上,如果非0會發生部分連接不上的情況!(可調用setsockopt設置套接字的linger延時標志,同時將延時時間設置為0。)
TIME_WAIT是TCP連接斷開時必定會出現的狀態。是無法避免掉的,這是TCP協議實現的一部分。
在WINDOWS下,可以修改注冊表讓這個時間變短一些,time_wait的時間為2msl,默認為4min.你可以通過改變TcpTimedWaitDelay的量,把它縮短到30s.TCP要保證在所有可能的情況下使得所有的數據都能夠被投遞。當你關閉一個socket時,主動關閉一端的socket將進入TIME_WAIT狀態,而被動關閉一方則轉入CLOSED狀態,這的確能夠保證所有的數據都被傳輸。但是這樣也會給我們帶來兩個問題 :
(1) 我們沒有任何機制保證最后的一個ACK能夠正常傳輸
(2) 網絡上仍然有可能有殘余的數據包(wandering duplicates),我們也必須能夠正常處理
解決方案 :
由于TIME_WAIT狀態所帶來的相關問題,我們可以通過設置SO_LINGER標志來避免socket進入TIME_WAIT狀態,這可以通過發送RST而取代正常的TCP四次握手的終止方式。但這并不是一個很好的主意,TIME_WAIT對于我們來說往往是有利的,下面我們來談談TIME_WAIT的作用
TIME_WAIT的作用 :
1. 可靠地實現TCP全雙工連接的終止;
如果服務器最后發送的ACK因為某種原因丟失了,那么客戶一定會重新發送FIN,這樣因為有TIME_WAIT的存在,服務器會重新發送ACK給客戶,如果沒有TIME_WAIT,那么無論客戶有沒有收到ACK,服務器都已經關掉連接了,此時客戶重新發送FIN,服務器將不會發送ACK,而是RST,從而使客戶端報錯。也就是說,TIME_WAIT有助于可靠地實現TCP全雙工連接的終止。
2. 允許老的重復分節在網絡中消逝。
如果沒有TIME_WAIT,我們可以在最后一個ACK還未到達客戶的時候,就建立一個新的連接。那么此時,如果客戶收到了這個ACK的話,就亂套了,必須保證這個ACK完全死掉之后,才能建立新的連接。也就是說,TIME_WAIT允許老的重復分節在網絡中消逝。
為什么TIME_WAIT 狀態需要保持2MSL這么長的時間?
ACK包到達服務器需要MSL時間,服務器重傳 FIN 包也需要MSL時間,2MSL 是數據包往返的最大時間,通常為2min,如果2MSL后還未收到服務器重傳的FIN 包,就說明服務器已經收到了ACK包,此時由TIME_WAIT狀態轉變為CLOSED狀態.
如果 TIME_WAIT 狀態保持時間不足夠長(比如小于2MSL),第一個連接就正常終止了。第二個擁有相同相關五元組的連接出現,而第一個連接的重復報文到達,干擾了第二個連接。TCP實現必須防止某個連接的重復報文在連接終止后出現,所以讓TIME_WAIT狀態保持時間足夠長(2MSL),連接相應方向上的TCP報文要么完全響應完畢,要么被丟棄。建立第二個連接的時候,不會混淆。
進程和線程有什么關系與區別(美團)
進程
每個應用程序都是一個進程,每個進程都有自己獨立的一塊內存空間,一個進程可以有多個線程。
進程的三種狀態:就緒態(以獲得除cpu外的所有資源),阻塞態,執行態
線程
進程中的一個執行任務(控制單元)。一個進程至少有一個線程,一個進程可以運行多個線程,多個線程可以共享數據。
區別
-
根本區別:進程是操作系統分配資源的基本單位,線程是處理器任務調度和執行的基本單位
-
資源開銷:每個進程都有獨立的代碼和數據空間,程序之間切換開銷大;線程是輕量級的線程,切換開銷少
-
內存分配:進程的地址空間和資源是相互獨立的,線程共享本進程的地址空間和資源
進程間的通信方式有哪些?(美團)
1.管道
1.1匿名管道(半雙工,數據只能單向移動,面向字節流,允許具有血緣關系的進程通信)
兩個文件描述符指向管道的兩端
1.2有名管道(半雙工,允許無親緣關系的進程通信)
2.消息隊列
(發送進程添加消息到隊列的末尾,接收進程在隊列頭部接收消息,消息一旦被接收就會從隊列中刪除,類似FIFO)
3.信號量
信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。
信號量工作原理 :
由于信號量只能進行兩種操作等待和發送信號,即P(sv)和V(sv),他們的行為是這樣的:
- P(sv):如果sv的值大于零,就給它減1;如果它的值為零,就掛起該進程的執行
- V(sv):如果有其他進程因等待sv而被掛起,就讓它恢復運行,如果沒有進程因等待sv而掛起,就給它加1.
在信號量進行PV操作時都為原子操作(因為它需要保護臨界資源)
4.共享內存
共享內存就是允許兩個或多個進程共享一定的存儲區。共享內存沒有任何的同步與互斥機制,所以要使用信號量來實現對共享內存的存取的同步
5.套接字
可用于不同機器間的進程通信
輸入一個網址,執行過程是怎樣的
如上圖所示,在瀏覽器的地址欄中輸入url : 此時執行過程簡單地介紹如下所示
第一步 : 我們的DNS域名解析器會對url進行域名解析,找到對應的IP節點進行返回
第二步 : 拿到我們訪問的IP,我們就要與對應的服務器建立TCP連接(三次握手)
第三步 : TCP連接建立成功,我們就可以向服務器發送HTTP請求了,當服務器獲取我們的請求,進行處理,然后將請求的響應返回給我們
第四步 : 關閉TCP連接(四次揮手)
1.DNS域名解析(找到ip地址)
DNS是進行域名和與之相對應的IP地址轉換的服務器
瀏覽器會首先搜索瀏覽器自身的DNS緩存,如果瀏覽器自身的緩存里面沒有找到對應的條目,
那么瀏覽器會搜索操作系統自身的DNS緩存,操作系統域名解析的過程是讀取hosts文件(位于C:\Windows\System32\drivers\etc),如果在hosts文件中也沒有找到對應的條目,
瀏覽器就會找TCP/IP參數中設置的首選DNS服務器(本地DNS服務器)發起一個DNS的系統調用(運營商dns-->根(13臺)域名服務器-->頂級域名服務器-->域名注冊商服務器)
從客戶端到本地DNS服務器是屬于遞歸查詢,而DNS服務器之間就是的交互查詢就是迭代查詢。
2.發起TCP三次握手,建立連接
3.發起http請求,服務器響應給瀏覽器html代碼
4.瀏覽器解析html代碼,并請求html代碼中的資源(如js,css,圖片等)
5.瀏覽器對頁面進行渲染呈現給用戶
將URL對應的各種資源,通過瀏覽器渲染引擎,輸出可視化的圖像
渲染引擎主要包括:html解析器,css解析器,布局,js引擎
html引擎:將html文本解釋成DOM樹(文檔對象模型)
css解釋器:為dom中的各個元素對象加上樣式信息(CSS對象模型)
布局:將dom和css樣式信息結合起來,計算他們的大小及位置信息,構建(渲染樹)
js引擎:解釋js代碼并把代碼邏輯對應的dom和css改動信息應用到布局中去
輸入一個網址之后會發生什么,用到了哪些協議
輸入一個網址以后,首先會進行DNS域名解析,找到目標的IP地址,然后和目標地址建立TCP連接,連接成功以后,發送HTTP請求,目標服務器處理完請求以后,返回響應結果,最后關閉TCP連接
網絡間兩個主機通信過程,用到了哪些設備
設存在兩個主機 : 主機A和主機B,網絡間主機A和主機B的通信過程分為兩種情況
情況1 : 主機A和主機B位于同一個二層網絡中,此時直接走二層交換機
主機A首先查看自己的ARP緩存,檢查是否含有主機B的IP到MAC地址的映射,如果存在映射,則構造報文,目的IP為主機B的IP,源IP為主機A的IP,目的MAC為主機B的MAC,源MAC為主機A的MAC,將報文發送給交換機C.交換機C進行MAC地址表學習,將主機A和MAC和報文入端口號記錄下來,然后交換機C查看自己的MAC轉發表,檢查是否含有主機B的MAC到端口的映射,如果有對應的端口,則獲取對應的端口,將報文從此端口轉發出去,報文到達主機B.如果交換機C沒有主機B的MAC轉發映射表,則采用洪泛的形式廣播報文,主機B收到報文后向主機A進行回復,交換機C進行MAC表學習,將主機B的MAC和報文入端口號記錄下來
如果主機A沒有主機B的ARP映射,主機A需要發送ARP請求,以獲取主機B的MAC,將報文發往交換機C,交換機C采用洪泛的形式廣播報文,主機B收到廣播報文后,在自己的ARP緩存表中寫入主機A的IP到MAC的映射,將自己的MAC封裝到ARP回復報文中,單播給主機A,主機A獲取到主機B的MAC后,在自己的ARP緩存表中寫入主機B的IP到MAC的映射,構造報文發送給主機B,過程同上。
主機B向主機A回復報文的過程類似。
情況2 : 主機A和主機B不在同一層網絡中,需要走三層路由器 + 二層交換機
主機A查看自己的ARP緩存表,檢查是否有路由器E的IP到MAC的映射,如果有映射,獲取路由器E的MAC,構造報文,目的IP為主機B的IP,源IP為主機A的IP,目的MAC為路由器E的MAC,源MAC為主機A的MAC,將報文通過交換機C發往路由器E,過程同上。 如果主機A沒有路由器E的IP到MAC的映射,需要發送ARP請求,獲取路由器E的MAC,過程同上。路由器E收到主機A的報文后,剝離報文的MAC幀頭,查詢路由表,發現目標主機B所在的網絡是直連的,查看自己的ARP緩存表,如果有主機B的IP到MAC的映射關系,獲取主機B的MAC,封裝報文MAC幀頭,目的MAC為主機B的MAC,源MAC為路由器E的MAC,將報文通過交換機D發往主機B,如果路由器E沒有主機B的IP到MAC的映射關系,需要發送ARP請求,獲取主機B的MAC,過程同上。
主機B向主機A回復報文的過程類似。
注意 :
- 路由器上的路由表一般是配置靜態路由或者通過路由協議自動學習的
ARP協議和ARP攻擊
ARP協議
ARP協議指的是地址解析協議(Address Resolution Protocol),是根據**IP地址獲取物理地址(MAC地址)**的一個TCP/IP協議.
在計算機間通信的時候,計算機要知道目的計算機是誰(就像我們人交流一樣,要知道對方是誰),這中間需要涉及到MAC地址,而MAC是真正的電腦的唯一標識符。
我們通過兩個主機之間的ping連接,來看一下簡單的ARP請求應答
PC1依據OSI模型 :
① 依次從上至下對數據進行封裝,包括對ICMP Date加IP包頭的封裝,但是到了封裝MAC地址的時候
② PC1首先查詢自己的ARP緩存表,發現沒有IP2和他的MAC地址的映射,這個時候MAC數據幀封裝失敗。我們使用ping命令的時候,是指定PC2的IP2的,計算機是知道目的主機的IP地址,能夠完成網絡層的數據封裝,因為設備通信還需要對方的MAC地址,但是PC1的緩存表里沒有,所以在MAC封裝的時候填入不了目的MAC地址。
那么PC1為了獲取PC2的MAC地址 :
③ PC1要發送詢問信息,詢問PC2的MAC地址,詢問信息包括PC1的IP和MAC地址、PC2的IP地址,這里我們想到一個問題,即使是詢問信息,也是需要進行MAC數據幀的封裝,那這個詢問信息的目的MAC地址填什么呢,規定當目的MAC地址為ff-ff-ff-ff-ff-ff時,就代表這是一個詢問信息,也即使后面我要說的廣播。
PC2收到這個詢問信息后,將這里面的IP1和MAC1(PC1的IP和MAC)添加到本地的ARP緩存表中,然后 :
④ PC2發送應答信息,對數據進行IP和MAC的封裝,發送給PC1,因為緩存表里已經有PC1的IP和MAC的映射了呢。這個應答信息包含PC2的IP2和MAC2。PC1收到這個應答信息,理所應當的就獲取了PC2的MAC地址,并添加到自己的緩存表中。
經過這樣交互式的一問一答,PC1和PC2都獲得了對方的MAC地址,值得注意的是,目的主機先完成ARP緩存,然后才是源主機完成ARP緩存。之后PC1和PC2就可以真正交流了。
ARP攻擊
對于交換機而言,它也具有記憶功能,會基于源MAC地址建立一個CAM緩存表(記錄MAC對應接口的信息),理解為當PC1發送消息至交換機的Port1時,交換機會把源MAC(也就是MAC1)記錄下來,添加一條MAC1和Port1的映射,之后交換機可以根據MAC幀的目的MAC進行端口轉發
ICMP協議
它是TCP/IP協議族的一個子協議,用于在IP主機、路由器之間傳遞控制消息。控制消息是指網絡通不通、主機是否可達、路由是否可用等網絡本身的消息。這些控制消息雖然并不傳輸用戶數據,但是對于用戶數據的傳遞起著重要的作用。
路由器和交換機的區別
(1)外形上:
交換機通常端口比較多看起來比較笨重,而路由器的端口就少得多體積也小得多
(2)工作層次不同:
最初的交換機工作在數據鏈路層,而路由器則工作網絡層
(3)數據的轉發對象不同:
交換機是根據MAC地址轉發數據幀,而路由器則是根據IP地址來轉發IP數據。
(4)”分工“不同
交換機主要是用于組建局域網,而路由器則是負責讓主機連接外網。
(5)沖突域和廣播域
交換機分割沖突域,但是不分割廣播域,而路由器分割廣播域。
(6)工作原理
交換機的原理比較簡單,一般都是采用硬件電路實現數據幀的轉發
路由器工作在網絡層,肩負著網絡互聯的重任,要實現更加復雜的協議,具有更加智能的轉發決策功能,一般都會在在路由器中跑操作系統,實現復雜的路由算法,更偏向于軟件實現其功能。
(7)安全性能
路由器一般有防火墻的功能,能夠對一些網絡數據包選擇性過濾。現在的一些路由器都具備交換機的功能,一些交換機具備路由器的功能,被稱為3層交換機,廣泛使用。相比較而言,路由器的功能較交換機要強大,但是速度也較慢,價格昂貴,三層交換機既有交換機的線性轉發報文的能力,又有路由器的良好的路由功能因此得到廣泛的使用
cdn (網易云音樂)(字節)
由于我們使用本地域名解析器進行解析,獲取源服務器IP導致每一次獲取數據,都要去源服務器進行訪問獲取,造成性能的損失的降低,故我們在網絡各處部署節點服務器,構建CDN系統,當我們使用本地DNS域名系統進行解析的時候,DNS系統會將域名解析交給CNAME指向的專用的DNS服務器,通過CDN的DNS服務器獲取到一臺合適的緩存服務器IP給我們,這里的合適性指的是(服務器距離我們的距離位置,該服務器上是否存在我們需要的內容等等…),此時我們就與該緩存服務器建立TCP連接,已經后續的HTTP請求獲取數據,得到響應等過程,如果該節點服務器不能滿足我們的需求,我們會層層向它的上級服務器進行訪問,直到源服務器為止.
cdn(內容分發網絡)
(Content Delivery Network)
就近訪問原理:采用各種緩存服務器,將這些緩存服務器分布到用戶訪問相對集中的地區或網絡,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的工作正常的緩存服務器上,由緩存服務器直接響應用戶請求。cdn就是用來加速的,他能讓用戶就近訪問數據,這樣就更更快的獲取到需要的數據。
舉個例子,現在服務器在北京,深圳的用戶想要獲取服務器上的數據就需要跨越一個很遠的距離,這顯然就比北京的用戶訪問北京的服務器速度要慢。但是現在我們在深圳建立一個cdn服務器,上面緩存住一些數據,深圳用戶訪問時先訪問這個cdn服務器,如果服務器上有用戶請求的數據就可以直接返回,這樣速度就大大的提升了。
代售點優勢:大部分請求在CDN邊緣完成,起到了分流的作用,減輕源站的負載。
dns(域名解析)
我們怎么知道用戶的所在位置從而給他分配最佳的cdn節點呢。這就需要dns服務來進行定位了。
當我們在瀏覽器中輸入一個域名時,首先需要將域名轉換為ip地址,再將ip地址轉換為mac地址,這樣才能在網絡上找到該服務器。當我們向dns服務器發起解析域名的請求時,dns服務器首先會查詢自己的緩存中有沒有該域名,如果緩存中存在該域名,則可以直接返回ip地址。如果緩存中沒有,服務器則會以遞歸的方式層層訪問。例如,我們要訪問www.baidu.com,首先我們會先向全球13個根服務器發起請求,詢問com域名的地址,然后再向負責com域名的名稱服務器發送請求,找到baidu.com,這樣層層遞歸,最終找到我們需要的ip地址。
dns劫持
DNS劫持又稱為域名劫持,是一種惡意攻擊,黑客或其他方通過使用流氓DNS服務器或其他策略來重定向用戶,該策略更改了Internet用戶被重定向到的IP地址。
防范DNS污染
DNS污染最常見的就是篡改host主機文件,通過篡改DNS主機文件ip地址和網址將不再一一對應,打開的網站將不是最初想要訪問的網站。
- 53端口為DNS服務器所開放,主要用于域名解析。如果開放DNS服務,黑客可以通過分析DNS服務器而直接獲取web服務器等主機的ip地址,在利用53端口突破某些不穩定的防火墻,從而實施攻擊。如果不用于提供域名解析服務,建議關閉該端口。
- 使用RNDC加密,存根區域,減少DNS的生命周期(RNDC是一種控制域名服務器的工具,通過網絡與DNS服務器進行連接,實現不停止DNS服務器工作的情況下進行數據更新)
- 檢查授權名稱服務器是否和主機上的解析一致。早期的互聯網連接需要進行反向地址解析,至今SMTP右鍵服務器還在使用。
DNS使用什么協議
DNS區域傳輸的時候使用TCP協議:
輔域名服務器會定時向主域名服務器進行查詢以便了解數據是否變動。如有變動,會執行一次區域傳送,進行數據同步。
域名解析時使用UDP協議:
客戶端向DNS服務器查詢域名,一般返回的內容都不超過512字節,用UDP傳輸即可。不用經過三次握手,這樣DNS服務器負載更低,響應更快。
cdn緩存的兩種方式
cdn中緩存了服務器上的部分資源。
-
服務器主動去更新緩存,cdn節點被動接受
-
另一種方式是當用戶請求的資源不存在時,cdn服務器向上游服務器發起請求,更新緩存,然后將數據返回給用戶,這種方式是cdn服務器主動,源站服務器被動。(一般采用這種方式)
Nginx反向代理
當我們與DNS域名解析器解析的IP服務器建立TCP連接以后,此時向其發送請求時,我們可以在其中建立Nginx反向代理,可以實現
負載均衡,屏蔽真實地址,安全管理,解決跨域問題,節約有效的IP資源,減少web服務器壓力,提高響應速度
Nginx是一個輕量級/高性能的反向代理Web服務器,他實現非常高效的反向代理、負載均衡.
使用Nginx的好處
- 保護了真實的web服務器,使得web服務器對外不可見。外網只能看到反向代理服務器,而反向代理服務器上并沒有真實數據,因此保護了web服務器的資源安全。
- 節約了有限的IP地址資源
企業內部所有的網站共享一個在Internet中注冊的IP地址,這些服務器分配私有地址,采用虛擬主機的方式對外提供服務。
- 減少web服務器壓力,提高響應速度
反向代理就是通常所說的web服務器加速,它是一種通過在繁忙的web服務器和外部網絡之間增加一個高速的web緩沖服務器來降低實際的web服務器的負載的一種技術。反向代理服務器會強制將外部網絡對要代理的服務器的訪問經過它,它會將從源服務器上獲取到的靜態內容緩存到本地,以便日后再收到同樣的信息請求時,直接將本地緩存的內容發給客戶端,減少后端web服務器的壓力,提高響應速度。
-
其他優點
請求的統一控制,包括設置權限,過濾規則等。
區分動態和靜態可緩存內容。
實現負載均衡,內部可以采用多臺服務器來組成服務器集群,外部還是可以采用一個地址訪問。
解決ajax跨域問題。
作為真實服務器的緩存,解決瞬間負載量大的問題。
配置簡單
占內存小,可實現高并發連接,處理響應快
Nginx的缺點
處理動態頁面很慢
為什么Nginx的性能這么高?
因為他的事件處理機制:異步非阻塞事件處理機制(運用了epoll模型,提供了一個隊列,排隊解決)
Nginx怎么處理請求的?
nginx接收一個請求后,首先由listen和server_name指令匹配server模塊,再匹配server模塊里的location,location就是實際地址
server {
# 第一個Server區塊開始,表示一個獨立的虛擬主機站點
listen 80; # 提供服務的端口,默認80
server_name localhost; # 提供服務的域名主機名
location / {
# 第一個location區塊開始
root html; # 站點的根目錄,相當于Nginx的安裝目錄
index index.html index.htm; # 默認的首頁文件,多個用空格分開
} # 第一個location區塊結果
什么是正向代理和反向代理?
-
正向代理類似一個跳板機,代理訪問外部資源。(正向代理就是一個人發送一個請求直接就到達了目標的服務器)
比如我們國內訪問谷歌,直接訪問訪問不到,我們可以通過一個正向代理服務器,請求發到代理服,代理服務器能夠訪問谷歌,這樣由代理去谷歌取到返回數據,再返回給我們,這樣我們就能訪問谷歌了
2.反向代理(Reverse Proxy)對外就表現為一個服務器。(反方代理就是請求統一被Nginx接收,nginx反向代理服務器接收到之后,按照一定的規則分發給了后端的業務處理服務器進行處理了)
實際運行方式是指以代理服務器來接受internet上的連接請求,然后將請求轉發給內部網絡上的服務器,并將從服務器上得到的結果返回給internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器
Nginx的應用場景
- http服務器。Nginx是一個http服務可以獨立提供http服務。可以做網頁靜態服務器。
- 虛擬主機。可以實現在一臺服務器虛擬出多個網站,例如個人網站使用的虛擬機。
- 反向代理,負載均衡。當網站的訪問量達到一定程度后,單臺服務器不能滿足用戶的請求時,需要用多臺服務器集群可以使用nginx做反向代理。并且多臺服務器可以平均分擔負載,不會應為某臺服務器負載高宕機而某臺服務器閑置的情況。
- Nginx 中也可以配置安全管理、比如可以使用Nginx搭建API接口網關,對每個接口服務進行攔截。
Nginx目錄結構有哪些?
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf # Nginx所有配置文件的目錄
│ ├── fastcgi.conf # fastcgi相關參數的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始備份文件
│ ├── fastcgi_params # fastcgi的參數文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒體類型
│ ├── mime.types.default
│ ├── nginx.conf # Nginx主配置文件,很重要!!!
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相關參數文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相關參數文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi臨時數據目錄
├── html # Nginx默認站點目錄
│ ├── 50x.html # 錯誤頁面優雅替代顯示文件,例如當出現502錯誤時會調用此頁面
│ └── index.html # 默認的首頁文件
├── logs # Nginx日志目錄
│ ├── access.log # 訪問日志文件
│ ├── error.log # 錯誤日志文件
│ └── nginx.pid # pid文件,Nginx進程啟動后,會把所有進程的ID號寫到此文件
├── proxy_temp # 臨時目錄
├── sbin # Nginx命令目錄
│ └── nginx # Nginx的啟動命令
├── scgi_temp # 臨時目錄
└── uwsgi_temp # 臨時目錄
其他計算機網絡問題
1. 你怎么理解認證和權限的,為什么使用jwt不使用session、cookie?
答: 首先當前我們的網絡存在很多的惡意攻擊,例如XSS,CSRF等等,我們客戶端給服務器發送請求,訪問服務器時,服務器需要對我們的請求進行相應的認證,同時對于我們客戶端授予不同的權限,擁有相應的權限才能訪問服務器,發送相應的請求信息。
1.1 對于jwt,我們首先需要了解它是什么?
jwt(Json web token) : 是為了在網絡應用環境中傳遞聲明而執行的一種基于JSON的開放標準(RFC 7519)
其中對應生成的token被設計成緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景
JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token可直接被用于認證,也可被加密。
1.2 JWT的組成
JWT生成編碼以后是以下的樣子:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
JWT由三個部分組成:
- 頭部(header)
- 載荷(payload)
- 簽證(signature)
頭部(header):
- 聲明類型,這里是jwt
- 聲明加密的算法,通常為HMAC算法
HMAC算法介紹:
完整的頭部head信息就像下面的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后我們會對頭部信息進行加密,構成第一部分:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
載荷(payload):
載荷是存放有效信息的地方,有效信息包括三個部分:
- 標準中注冊的聲明
- 公共的聲明
- 私有的聲明
其中,標準中注冊的聲明(建議但是不強制使用) :
- iss: jwt簽發者
- sub: jwt所面向的用戶
- aud: 接收jwt的一方
- exp: jwt的過期時間,這個過期時間必須要大于簽發時間
- nbf: 定義在什么時間之前,該jwt都是不可用的.
- iat: jwt的簽發時間
- jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
公共的聲明:
- 可以添加任何信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.
私有聲明:
- 提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息
我們這里定義一個payload:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
進行加密處理以后,構成第二部分:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
簽證(signature):
jwt的第三部分是一個簽證信息,一般由三個部分組成:
- header(加密以后的)
- payload(加密以后的)
- secret
UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q
其中密鑰是保存在服務端的,服務端會根據這個密鑰生成token和驗證,所以必須要保存好!!!
1.3 簽名的目的:
最后一步簽名的過程,實際上是對頭部以及載荷內容進行簽名。一般而言,加密算法對于不同的輸入產生的輸出總是不一樣的。對于兩個不同的輸入,產生同樣的輸出的概率極其地小.
所以,如果有人對頭部以及載荷的內容解碼之后進行修改,再進行編碼的話,那么新的頭部和載荷的簽名和之前的簽名就將是不一樣的。而且,如果不知道服務器加密的時候用的密鑰的話,得出來的簽名也一定會是不一樣的.
服務器應用在接受到JWT后,會首先對頭部和載荷的內容用同一算法再次簽名。那么服務器應用是怎么知道我們用的是哪一種算法呢?別忘了,我們在JWT的頭部中已經用alg字段指明了我們的加密算法了。
如果服務器應用對頭部和載荷再次以同樣方法簽名之后發現,自己計算出來的簽名和接受到的簽名不一樣,那么就說明這個Token的內容被別人動過的,我們應該拒絕這個Token,返回一個HTTP 401 Unauthorized響應。
注意:
- 在JWT中不應該在載荷中存放任何敏感的信息,比如用戶的密碼等等
1.4 JWT如何使用?
一般會在請求頭中加入Authoriation,并加入Bearer標注:
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
服務端會驗證token,如果驗證通過就會返回相應的資源!
1.5 JWT的安全相關
- 不應該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
- 保護好secret私鑰,該私鑰非常重要。
- 如果可以,請使用https協議
1.6 對Token認證的五點認識:
- 一個Token就是一些信息的集合;
- 在Token中包含足夠多的信息,以便在后續請求中減少查詢數據庫的幾率;
- 服務端需要對cookie和HTTP Authrorization Header進行Token信息的檢查;
- 基于上一點,你可以用一套token認證代碼來面對瀏覽器類客戶端和非瀏覽器類客戶端;
- 因為token是被簽名的,所以我們可以認為一個可以解碼認證通過的token是由我們系統發放的,其中帶的信息是合法有效的;
2. JWT認證和傳統的Session認證的比較
2.1 傳統的session認證
我們知道,http協議本身是一種無狀態的協議,而這就意味著如果用戶向我們的應用提供了用戶名和密碼來進行用戶認證,那么下一次請求時,用戶還要再一次進行用戶認證才行,因為根據http協議,我們并不能知道是哪個用戶發出的請求,所以為了讓我們的應用能識別是哪個用戶發出的請求,我們只能在服務器存儲一份用戶登錄的信息,這份登錄信息會在響應時傳遞給瀏覽器,告訴其保存為cookie,以便下次請求時發送給我們的應用,這樣我們的應用就能識別請求來自哪個用戶了,這就是傳統的基于session認證。
2.2 基于session認證所顯露的問題
Session: 每個用戶經過我們的應用認證之后,我們的應用都要在服務端做一次記錄,以方便用戶下次請求的鑒別,通常而言session都是保存在內存中,而隨著認證用戶的增多,服務端的開銷會明顯增大。
擴展性: 用戶認證之后,服務端做認證記錄,如果認證的記錄被保存在內存中的話,這意味著用戶下次請求還必須要請求在這臺服務器上,這樣才能拿到授權的資源,這樣在分布式的應用上,相應的限制了負載均衡器的能力。這也意味著限制了應用的擴展能力。
CSRF: 因為是基于cookie來進行用戶識別的, cookie如果被截獲,用戶就會很容易受到跨站請求偽造的攻擊。
2.3 基于token的鑒權機制
基于token的鑒權機制類似于http協議也是無狀態的,它不需要在服務端去保留用戶的認證信息或者會話信息。這就意味著基于token認證機制的應用不需要去考慮用戶在哪一臺服務器登錄了,這就為應用的擴展提供了便利。
它的流程如下所示:
- 用戶使用用戶名和密碼來請求服務器
- 服務器進行驗證用戶的信息
- 服務器通過驗證發送給用戶一個token
- 客戶端存儲token,并在每次請求時附上這個token值
- 服務端驗證token值,并返回數據
這個token值必須在每次請求時傳遞給服務端,它應該保存在請求頭中,另外,服務端要支持CORS(跨來源資源共享)策略,一般我們在服務端這么做就可以了(Access-Control-Allow-Origin)
2.4 token方式的優點
- 支持跨域訪問: Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸的用戶認證信息通過HTTP頭傳輸。
- 無狀態(也稱:服務端可擴展行):Token機制在服務端不需要存儲session信息,因為Token 自身包含了所有登錄用戶的信息,只需要在客戶端的cookie或本地介質存儲狀態信息。
- 更適用CDN: 可以通過內容分發網絡請求你服務端的所有資料(如:javascript,HTML,圖片等),而你的服務端只要提供API即可。
- 去耦: 不需要綁定到一個特定的身份驗證方案。Token可以在任何地方生成,只要在你的API被調用的時候,你可以進行Token生成調用即可。
- 更適用于移動應用: 當你的客戶端是一個原生平臺(iOS, Android,Windows 8等)時,Cookie是不被支持的(你需要通過Cookie容器進行處理),這時采用Token認證機制就會簡單得多。
- CSRF:因為不再依賴于Cookie,所以你就不需要考慮對CSRF(跨站請求偽造)的防范。
- 性能: 一次網絡往返時間(通過數據庫查詢session信息)總比做一次HMACSHA256計算 的Token驗證和解析要費時得多。
- 不需要為登錄頁面做特殊處理: 如果你使用Protractor 做功能測試的時候,不再需要為登錄頁面做特殊處理。
- 基于標準化:你的API可以采用標準化的 JSON Web Token (JWT). 這個標準已經存在多個后端庫(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)。
- 因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
- 因為有了payload部分,所以JWT可以在自身存儲一些其他業務邏輯所必要的非敏感信息。
- 便于傳輸,jwt的構成非常簡單,字節占用很小,所以它是非常便于傳輸的。
- 它不需要在服務端保存會話信息, 所以它易于應用的擴展。
2.5 java實現JWT
2.6 JWT和SpringSecurity的比較
JWT的優點:
- 無需再服務端存儲用戶數據,減輕服務端壓力
- 輕量級,json風格,比較簡單
- 跨語言
JWT的缺點:
- token一旦簽發,無法修改
- 無法更新token有效期,用戶登錄狀態刷新難以實現
- 無法銷毀一個token,服務端不能對用戶狀態進行絕對控制
- 不包含權限控制
SpringSecurity的優點:
- 用戶信息保存在服務端,服務端可以對用戶狀態絕對控制
- 基于Spring,無縫整合,修改登錄邏輯,其實就是添加過濾器
- 整合權限管理
SpringSecurity的缺點:
- 實現復雜,基于一連串的過濾器鏈
- 需要再服務端保存用戶信息,增加服務端壓力
2.7 使用JWT做登錄認證,如何解決token的注銷問題
方案1 : 適當減短token的有效期,讓token盡快失效
方案2 : 使用redis (即使用JWT還要使用redis的場景)
(1) 我們在用戶登錄時,生成JWT
(2) 把JWT的id存儲到redis中,只有redis數據庫中有id的JWT,才是有效的JWT
(3) 退出登錄時,將對應的id從redis中刪除,即間接解決了token的注銷問題
2.8 如何解決異地登錄問題?
答:JWT設計為了實現無狀態的登錄,因此token無法修改,難以實現異地登錄的判斷,或者強制讓登錄token失效。
因此如果有類似需求, 就不應選擇JWT作為登錄方案,而是使用傳統session登錄方案。
但是,如果一定要用JWT實現類似要過,就需要在Redis中記錄登錄用戶的JWT的token信息,這樣就成了有狀態的登錄,但是這樣還不如一開始就選擇Session方案.
2.9 你覺得在微服務中是在微服務中實現認證和登錄好還是在網關中實現好,為什么?
我們一般選擇在網關中實現認證和登錄.
我們的微服務隱藏在網關的后面,而且整個服務被Nginx反向代理,用戶只能看到nginx的地址,微服務暴露的可能性很低。
然后,即便真的暴露了,我們的微服務都做了嚴格的服務間鑒權處理,任何對微服務的訪問都會被驗證是否有授權,如果沒有則會被攔截。具體實現:
- 會有一張表記錄每個微服務的id,和密鑰信息
- 服務啟動時,需要去授權中心,認證身份,攜帶id和secret
- 授權中心認證通過,會頒發一個JWT給微服務
- 微服務訪問其它服務時,需要攜帶JWT
- 被訪問的服務,需要驗證JWT,如果沒有攜帶,或token時偽造的直接攔截請求即可
3. Session和Cookie的面試題
3.1 會話
當一個用戶打開一個瀏覽器或者訪問一個網站時,只要不關閉這個瀏覽器,不管該用戶點擊多少個超鏈接,訪問多少個資源,直到該用戶關閉瀏覽器或者服務器關閉.這樣一個過程稱為一個會話.
那么在會話過程中需要解決一些問題 : 主要就是保存用戶在訪問過程中產生的數據
3.2 Cookie(瀏覽器端會話技術)
-
當瀏覽器第一次訪問服務器,給服務器發送請求時,服務器端會創建一個鍵值對形式的Cookie,該Cookie中會包含當前用戶的信息,然后通過響應(響應頭set-cookie)返回給瀏覽器端,cookie會保存在瀏覽器端
-
下次訪問的時候,瀏覽器會攜帶服務器端創建的cookie(請求頭cookie),服務器端就可以拿到這些cookie攜帶的數據區分不同的用戶,并拿到對應的信息
注意:
- cookie不能跨瀏覽器
- cookie不支持中文
3.3 Session(服務器端會話技術)
- 瀏覽器端第一次發送請求到服務器端,服務器端會創建一個Session,同時會創建一個特殊的Cookie(name: JSESSIONID ,value: sessionid),然后將該cookie發送給瀏覽器端
- 當瀏覽器端下次訪問服務器端時,都會攜帶這份JSESSIONID的Cookie對象
- 服務器端會根據對應的sessionid會查詢Session對象,從而區分不同的用戶
session的生命周期
-
創建 : 第一次訪問服務器,調用getSession()方法獲取session會話的時候
-
銷毀 : (1) 服務器非正常關閉 (2) 設置超時時間(默認tomat服務器是30分鐘) (3)瀏覽器關閉(手動銷毀)
3.4 Cookie和Session的區別
- 數據保存的位置不同 : Cookie數據保存在客戶端,而Session數據保存在服務器端
- 安全性不同 : cookie信息一般是以明文的方式存放在客戶端的,安全性比較低,可以通過一個加密算法進行加密存放;session信息存放在服務器的內存中,安全性較好(所以我們一般將用戶密碼等安全級別較高的信息存放在session中)
- 存儲大小的限制 : 單個cookie在客戶端的限制為4k,就是說一個站點在客戶端存放的cookie不能超過3k;session一般沒有限制,存放在服務器端的內存中,但是訪問過多,會增加服務器的內存和性能.
- cookie為多個用戶瀏覽器共享; session為一個用戶瀏覽器獨享
3.5設置失效時間
session:
關閉瀏覽器,只會使瀏覽器中的sessionid消失,但不會使服務端的session對象消失。因此服務端需要設置一個過期時間,當距離客戶上一次使用session的時間超過了這個失效時間時就認為客戶端已經停止了活動,從而刪除session。session.setMaxInactiveInterval(3600);
cookie:
- 當設置失效時間大于1天時
Cookies.set('name', 'value', {
expires: 7, //設置失效時間為7天
});
- 當設置失效時間小于1天時,需要在當前時間上加上失效時間
var millisecond = new Date().getTime();
var expiresTime = new Date(millisecond + 60 * 1000 * 15); //設置過期時間為15分鐘后
Cookies.set('name', 'value', {
expires: expiresTime, //如果設置一個過去的時間點會直接刪除
});
4.sessionStorage和localStorage的區別
sessionStorage和localStorage均用于客戶端本地存儲數據
localStroage
不能設置過期時間。生命周期是永久性的,即使關閉瀏覽器也不會讓數據消失,除非主動去刪除數據。
if(window.localStroage){
//判斷瀏覽器是否支持localstroage
window.localStroage.setItem('name','zs') //存儲數據
window.localStroage.getItem('name') //獲取數據
window.localStroage.removeItem('name') //移除數據
}
sessionStroage
生命周期是在瀏覽器關閉前,在瀏覽器關閉前,其數據一直存在。使用方法與localStroage一致。
- 頁面刷新不會消除數據
- 只有在當前頁面打開的鏈接,才可以訪問sessionStroage
5.垃圾回收機制(招銀網絡)
標記清除
當變量進入環境時,例如:在一個函數中聲明一個變量,就將這個變量標記為“進入環境”;當變量離開時,則將其標記為離開環境。
(從邏輯上講,永遠不能釋放進入環境的變量所占的內存,因為只要執行流進入相應的環境,就可能還會用到它們)
引用計數
跟蹤記錄每個值被引用的次數。
當申明了一個變量并將一個引用類型值A賦給該變量時,則這個引用類型值A的引用次數就是1。如果同一個引用類型值A被賦給另一個變量,則這個引用類型值A的引用次數+1;相反,如果包含這個引用類型值A的變量又取得了另外一個引用類型值B,則這個引用類型值A的引用次數-1;當這個值的引用次數變成 0 時,則說明沒有辦法再訪問這個值了,因而就可以將其占用的內存空間回收回來。
循環引用
function circularReference() {
let obj1 = {
};
let obj2 = {
b: obj1
};
obj1.a = obj2;
}
//當obj1這個變量指向obj1這個對象時,obj1這個對象的引用計數為1
//當obj2這個變量指向obj2這個對象時,obj2這個對象的醫用計數為1;obj2中的b屬性指向obj1,obj1這個對象的引用計數變為2
//obj1的a屬性指向obj2,obj2這個對象的引用計數變為2
//當代碼執行完畢,會將obj1和obj2賦值為null,但此時obj1對象和obj2對象的引用計數仍為1,不為0,所以不會進行垃圾回收,造成垃圾泄露。
//這兩個對象已經沒什么作用了,在函數外部也訪問不到他們。
深拷貝如何解決循環引用(騰訊)
解決問題的關鍵也就是可以將這些引用存儲起來并在發現引用時返回被引用過的對象,從而結束遞歸的調用。
原理:
利用uniqueList存儲拷貝過的對象,如果之前拷貝過就把他的拷貝結果返回,否則遍歷該對象的各個屬性,是對象的話繼續深拷貝,不是對象就直接賦值
//arr中存儲了多個對象
//[{source:xxx, target:xxx},{source:xxx, target:xxx},]
function find(arr,item){
for(var i=0; i<arr.length; i++){
if(arr[i].source === item){
return arr[i] //返回的是這整個對象{source:xxx, target:xxx}
}
}
return null;
}
function isObject(obj) {
return typeof obj === 'object' && obj != null;
}
function deepClone(source,uniqueList){
//被拷貝的source必須是對象
if(!isObject(source)) return source;
if(!uniqueList) uniqueList = []; //初始化數據
//存儲結果
var target = Array.isArray(source) ? [] : {
};
var uniqueData = find(uniqueList,source); //在初始化數據中查看是否存在source
if(uniqueData) return uniqueData.target;
uniqueList.push({
source:source, //拷貝源
target:target //拷貝結果
});
for(var key in source){
if(Object.prototype.hasOwnProperty.call(source,key)){
if(isObject(source[key])){
target[key] = deepClone(source[key], uniqueList) // 傳入數組
}else{
target[key] = source[key];
}
}
}
return target;
}
var a = {
name:"key1",
eat:[
"蘋果",
"香蕉"
]
}
a.eat[2] = "桃";
a.d = a;
console.log(a);
//{name: "key1", eat: Array(3), d: {
// {name: "key1", eat: Array(3), d: {…}}
//}}
b = deepClone(a);
console.log(b);
//{name: "key1", eat: Array(3), d: {
// {name: "key1", eat: Array(3), d: {…}}
//}}
6.跨域
同源策略是瀏覽器最核心也是最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。
同源是指”協議+域名+端口“三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。
JsonP
通常為了減輕web服務器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的服務器上,在html頁面中再通過相應的標簽從不同域名下加載靜態資源,而被瀏覽器允許,基于此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域通信。
缺點:只能實現get一種請求
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參一個回調函數名給后端,方便后端返回時執行這個在前端定義的回調函數
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回調執行函數
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
服務端返回如下(返回時即執行全局函數):
handleCallback({
"status": true, "user": "admin"})
后端node.js代碼示例:
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var params = qs.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回設置
res.writeHead(200, {
'Content-Type': 'text/javascript' });
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
跨域資源共享CORS
主要是后端設置,如果前端發送請求需要攜帶cookie,前端才需要設置
前端設置:
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端設置是否帶cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
后端設置
/* * 導入包:import javax.servlet.http.HttpServletResponse; * 接口參數中定義:HttpServletResponse response */
// 允許跨域訪問的域名:若有端口需寫全(協議+域名+端口),若沒有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允許前端帶認證cookie:啟用此項后,上面的域名不能為'*',必須指定具體的域名,否則瀏覽器會提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS預檢時,后端需要設置的兩個常用自定義頭
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
nginx代理
同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議,不會執行JS腳本,不需要同源策略,也就不存在跨越問題。
前端請求:
var xhr = new XMLHttpRequest();
// 前端開關:瀏覽器是否讀寫cookie
xhr.withCredentials = true;
// 訪問nginx中的代理服務器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
代理服務器處理請求:
#proxy服務器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 當用webpack-dev-server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用
add_header Access-Control-Allow-Origin http://www.domain1.com; #當前端只跨域不帶cookie時,可為*
add_header Access-Control-Allow-Credentials true;
}
}
后臺:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var params = qs.parse(req.url.substring(2));
// 向前臺寫cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:腳本無法讀取
});
res.write(JSON.stringify(params));
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
nodejs中間件代理(vue框架)
//在webpack.config.js中配置
module.exports = {
entry: {
},
module: {
},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.domain2.com:8080', // 代理跨域目標接口
changeOrigin: true,
secure: false, // 當代理某些https服務報錯時用
cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改
}],
noInfo: true
}
}
提示OPTIONS預檢時,后端需要設置的兩個常用自定義頭
response.setHeader(“Access-Control-Allow-Headers”, “Content-Type,X-Requested-With”);
### nginx代理
> 同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。**服務器端調用HTTP接口**只是使用HTTP協議,不會執行JS腳本,不需要同源策略,也就**不存在跨越問題。**
前端請求:
```js
var xhr = new XMLHttpRequest();
// 前端開關:瀏覽器是否讀寫cookie
xhr.withCredentials = true;
// 訪問nginx中的代理服務器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
代理服務器處理請求:
#proxy服務器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 當用webpack-dev-server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用
add_header Access-Control-Allow-Origin http://www.domain1.com; #當前端只跨域不帶cookie時,可為*
add_header Access-Control-Allow-Credentials true;
}
}
后臺:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var params = qs.parse(req.url.substring(2));
// 向前臺寫cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:腳本無法讀取
});
res.write(JSON.stringify(params));
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
nodejs中間件代理(vue框架)
//在webpack.config.js中配置
module.exports = {
entry: {
},
module: {
},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.domain2.com:8080', // 代理跨域目標接口
changeOrigin: true,
secure: false, // 當代理某些https服務報錯時用
cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改
}],
noInfo: true
}
}
總結
以上是生活随笔為你收集整理的计算机网络面试题汇总(什么是计算机)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gfa是什么数字货币
- 下一篇: 宝可梦剑盾在哪捕捉小木灵 小木灵捕捉位置