1、HTTP
HyperText Transfer Protocol,用於傳輸HTML等內容的應用層協議,規定了瀏覽器和服務器之間如何通信以及通信時的數據格式
HTTPS 原理 (HTTPS = HTTP + SSL)
Http 是明文傳輸,不安全,
HTTPS 並不是新協議,而是讓 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是說
HTTPS 使用了隧道進行通信。通過使用 SSL,HTTPS 具有了加密(防竊聽)、可靠認證(防偽裝)和完整性保護(防篡改)三大特點。
SSL稱為安全套接字層,它位於傳輸層和應用層之間,為 Https 提供加密,認證,和完整性保護等服務。
HTTPS 采用的加密方式
HTTPS 采用混合的加密機制,使用非對稱密鑰加密傳輸對稱密鑰來保證傳輸過程的安全性,之后使用對稱密鑰
加密進行通信來保證通信過程的效率。如果單獨使用非對稱秘鑰的話每次加密和解密的時間開銷太大,如果單獨使用對稱加密的話,可靠性不夠,容易被竊聽攔截后破解,所以同時使用對稱加密和非對稱加密。
HTTPS 建立連接的具體過程:
1. client向server發送請求,然后連接到server的443端口,發送的信息主要是隨機值1和客戶端支持的加密算法。
2. server接收到信息之后給予client握手信息和數字證書,握手信息包括隨機值2和匹配好的協商加密算法,而數字證書就是公鑰。
3. 客戶端解析證書,首先會驗證公鑰是否有效,比如頒發機構,過期時間等等,如果發現異常,則會彈出一個警告框,提示證書存在問題。如果證書沒有問題,那么就生成一個隨即值(預主秘鑰),
接下來是通過隨機值1、隨機值2和預主秘鑰組裝會話秘鑰。然后通過證書的公鑰加密會話秘鑰。
傳送這個會話秘鑰信息。
4. 服務端通過私鑰解密得到隨機值1、隨機值2和預主秘鑰,然后根據剛才協商好的加密算法組裝成
會話秘鑰。
5. 客戶端通過會話秘鑰加密一條消息發送給服務端,主要驗證服務端是否正常接受客戶端加密的消息。
6. 同樣服務端也會通過會話秘鑰加密一條消息回傳給客戶端,如果客戶端能夠正常接受的話表明SSL層連接建立完成了。
HTTPS 的缺點
- 因為需要進行加密解密等過程,因此速度會更慢;
- 需要支付證書授權的高額費用。
HTTP 和 HTTPS 的區別
1、HTTPS 需要支付證書授權的高額費用
2、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。(這個只是默認端口不一樣,實際上端口是可以改的)
2、HTTP請求報文與響應報文格式
請求報文包含三部分:
a、請求行:包含請求方法、URI、HTTP版本信息
b、請求首部字段
c、請求內容實體
響應報文包含三部分:
a、狀態行:包含HTTP版本、狀態碼、狀態碼的原因短語
b、響應首部字段
c、響應內容實體
3、Http協議中有哪些請求方式?
GET:用於請求訪問已經被URI(統一資源標識符)識別的資源,可以通過URL傳參給服務器
POST:用於傳輸信息給服務器,主要功能與GET方法類似,但一般推薦使用POST方式
PUT:傳輸文件,報文主體中包含文件內容,保存到對應URI位置
HEAD:獲得報文首部,與GET方法類似,只是不返回報文主體,一般用於驗證URI是否有效
DELETE:刪除文件,與PUT方法相反,刪除對應URI位置的文件
OPTIONS:查詢響應URI支持的HTTP方法
4、在瀏覽器中輸入url地址 ->> 顯示主頁的過程(面試常客)
打開一個網頁,整個過程會使用哪些協議
圖解(圖片來源:《圖解HTTP》):
總體來說分為以下幾個過程:
- DNS解析,將域名解析為ip地址,這個ip的查找過程又分成三種情況:瀏覽器緩存、路由器緩存、DNS緩存
- TCP連接,用到了IP協議、OSPF協議、ARP協議
- 發送HTTP請求 ,用到了HTTP協議,瀏覽器將用戶的數據封裝到cookies中,並將cookie封裝到一個http請求中,如果網頁中存在多個url請求,會在本次tcp連接請求中發起多次http請求。
- 服務器處理請求並生成一個html響應,將這個響應封裝到一個http報文中並並返回HTTP報文
- 瀏覽器解析渲染頁面
- 連接結束
ARP(Address Resolution Protocol)是地址解析協議
5、一次tcp連接中可以發送多少次 http 請求
如果是 http 1.0 則只能發一次,因為http1.0 是短連接,默認發送一次 http 請求就會斷開連接,除非設置Connection: keep-alive
如果是 http 1.1 則可以發多次,因為http1.1 是長連接,只有客戶端和服務器有一個發出斷開連接的請求才會斷開連接。
6、HTTP1.0和HTTP1.1的區別
1. 長連接
HTTP1.0
默認是短連接,發送一次 http 請求就會斷開連接,除非設置Connection: keep-alive,而 在HTTP1.1中默認開啟長連接keep-alive,
在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲。
2. 節約帶寬
HTTP 1.1 支持只發送header 信息和斷點續傳功能。節約了帶寬。
3. HOST域
因為一個 iP 地址可能存在多台虛擬主機,所以發送請求時必須指明虛擬主機的主機號。
7、HTTP1.1 和 HTTP 2.0 的區別
1. 多路復用
HTTP2.0使用了多路復用的技術,做到同一個連接並發處理多個請求
2. 頭部壓縮
HTTP1.1不支持header數據的壓縮,只會壓縮消息主題,HTTP2.0支持對header的數據進行壓縮,這樣數據體積更小了,在網絡上傳輸就會更快。
3. 服務器推送
也就是我們常說的預加載功能,允許服務器將當前網頁所用的其他資源提前加載到瀏覽器,而不必等我們點擊這個資源時再發起請求。這樣可以降低延遲。
8、TCP三次握手
- 客戶端–發送 SYN 標志位為 1 , 序列號為 x 的數據包–一次握手–服務端,客戶端進入同步發送狀態
- 服務端–發送帶有 SYN/ACK 標志的數據包–二次握手–客戶端,服務端進入同步接收狀態
- 客戶端–發送帶有帶有 ACK 標志的數據包–三次握手–服務端,客戶端進入連接狀態,服務端收到這個確認報文后也進入連接狀態。
為什么要三次握手,兩次可以嗎?
第三次握手的過程是客戶端對服務器發送的確認連接進行確認,是為了防止失效的連接請求到達服務器后,讓服務器錯誤打開連接。
客戶端發送的連接請求如果在網絡中滯留,那么就會隔很長一段時間才能收到服務器端發回的連接確認。客戶端等待
一個超時重傳時間之后,就會重新請求連接。但是這個滯留的連接請求最后還是會到達服務器,如果不進行三次握
手,每當服務器收到一個請求發送確認后就打開連接,那么服務器就會打開兩個連接。如果有第三次握手,在已經建立連接的情況下,客戶端會忽略服務器之后發送的對滯留連接請求的連接確
認,不進行第三次握手,因此就不會再次打開連接。
如果第三次握手失敗,即客戶端發送的 ASK 確認包丟失怎么辦
如果此時ACK在網絡中丟失,那么Server端該TCP連接的狀態為SYN_RECV,並且依次等待3秒、6秒、12秒后重新發送SYN+ACK包,以便Client重新發送ACK包。
Server重發SYN+ACK包的次數,可以通過設置/proc/sys/net/ipv4/tcp_synack_retries修改,默認值為5。 如果重發指定次數后,仍然未收到ACK應答,那么一段時間后,Server自動關閉這個連接。
但是Client認為這個連接已經建立,如果Client端向Server寫數據,Server端將以RST包(用於強制關閉tcp連接)響應,方能感知到Server的錯誤。
RST是
TCP 首部的一個志位,表示復位,用來異常的關閉連接,只要發送端覺得連接異常就會發送 RST 包,接收端收到這個包后就會馬上斷開連接。
什么是 syn - Flood 攻擊
攻擊方通過頻繁的切換ip或者利用大量的 ip 向服務器發起大量的半連接請求,每次連接都只完成第二次握手,從而讓服務器頻繁的重發連接確認,
大量的半連接信息將
消耗服務器大量的系統資源和網絡帶寬,這樣服務器就多余的資源
接收正常客戶的請求
解決辦法:
- 縮短超時(SYN Timeout)時間
- 增加最大半連接數
- 過濾網關防護
目前最流行也是最好用的攻擊方法就是使用SYN-Flood進行攻擊,SYN-Flood也就是SYN洪水攻擊。SYN-Flood不會完成TCP三次握手的第三步,也就是不發送確認連接的信息給服務器。這樣,服務器無法完成第三次握手,但服務器不會立即放棄,服務器會不停的重試並等待一定的時間后放棄這個未完成的連接,這段時間叫做SYN timeout,這段時間大約30秒-2分鍾左右。一個服務器若是處理這些大量的半連接信息而消耗大量的系統資源和網絡帶寬,這樣服務器就不會再有空余去處理普通用戶的正常請求(因為客戶的正常請求比率很小)。這樣這個服務器就無法工作了。
如果已經建立了連接,但是客戶端突然出現故障了怎么辦?
TCP還設有一個保活計時器,。服務器每收到一次客戶端的請求后都會重新復位這個計時器,時間通常是設置為2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以后每隔75秒鍾發送一次。若一連發送10個探測報文仍然沒反應,服務器就認為客戶端出了故障,接着就關閉連接。
9、TCP四次揮手過程
A 發送 FIN 標志位為 1, 序列號為 u 的連接釋放報文,進入等待fin 報文的第一個階段
B 收到之后發出確認,此時 TCP 屬於半關閉狀態,客戶端在收到這個確認進入 等待 Fin 報文的第二個階段。B 能向 A 發送數據但是 A 不能向 B 發送數據。
當 B 不再需要連接時,發送連接釋放報文,FIN=1。服務端進入最后確認階段
A 收到后發出確認,進入 TIME-WAIT 狀態,等待 2 MSL(最大報文存活時間)后釋放連接。
B 收到 A 的確認后釋放連接。
為什么需要第四次揮手--(防止出現單方向沒有釋放連接)
假設只有三次揮手,也就是說服務端在發送完數據就向客戶端發送一個帶有 FIN 信號的報文,之后服務端徹底關閉連接,但是如果這個 FIN 報文丟失了,客戶端沒有收到這個報文, 客戶端就會以為服務端仍有數據要發送,不會關閉連接。所以我們需要第四次揮手,讓客戶端收到 FIN 報文后發送一個確認報文,確認自己收到了關閉的信號,這樣服務端在收到這個報文后就可以徹底關閉連接了。
TIME_WAIT
客戶端接收到服務器端的 FIN 報文后進入此狀態,此時並不是直接進入 CLOSED 狀態,還需要等待一個時間計時器
設置的時間 2MSL。這么做有兩個理由:
- 確保最后一個確認報文能夠到達。如果 B 沒收到 A 發送來的確認報文,那么就會重新發送連接釋放請求報文,A 等待一段時間就是為了處理這種情況的發生。
- 等待一段時間是為了讓本連接持續時間內所產生的所有報文都從網絡中消失,使得下一個新的連接不會出現舊的連接請求報文。因為報文段有生存時間,當連接關閉時,有可能收到遲到的報文段。這時,若立馬就建立新的連接(同一端口),那么新的連接就會接收遲到的報文,誤以為是發給自己的。
如何統計time_wait的次數
兩種方式,awk語句或者netstat|grep time_wait|wc -l
MSL
MSL是Maximum Segment Lifetime英文的縮寫,中文可以譯為“報文最大生存時間”,他是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。因為tcp報文(segment)是ip數據報(datagram)的數據部分,具體稱謂請參見《數據在網絡各層中的稱呼》一文,而ip頭中有一個TTL域,TTL是time to live的縮寫,中文可以譯為“生存時間”,這個生存時間是由源主機設置初始值但不是存的具體時間,而是存儲了一個ip數據報可以經過的最大路由數,每經過一個處理他的路由器此值就減1,當此值為0則數據報將被丟棄,同時發送ICMP報文通知源主機。RFC 793中規定MSL為2分鍾,實際應用中常用的是30秒,1分鍾和2分鍾等。
CLOSE_WAIT
服務器收到客戶端發送來的 釋放連接信號后,對這個信號進行確認,隨后進入這個CLOSE_WAIT半關閉狀態,此時服務端可以繼續 向客戶端發送數據,但是客戶端不能向服務端發送數據。
10、TCP有哪些特性保證了其可靠性,其中哪一個可以去掉
TCP協議保證數據傳輸可靠性的方式主要有:
校驗和、序列號、確認應答、超時重傳、連接管理、流量控制、擁塞控制
- 校驗和:保證數據的正確性
- 序列號:保證了針對數據包到達接收端主機順序
確認應答和超時重傳保證了 tcp 的可靠傳輸,連接管理中的三次握手和四次揮手保證了連接的正確建立和釋放,流量控制和擁塞控制保證了客戶端或者服務端能夠來得及接受數據,並且不會出現網絡擁堵。
- 超時重傳:針對數據包丟失或者出現定時器超時
- 連接管理:三次握手與四次揮手
- 流量控制:針對避免網絡擁堵時候;針對高效傳輸數據包的流動窗口的控制
- 擁塞控制:針對剛開始啟動的時候避免一下子發送大量數據包而導致網絡癱瘓的慢啟動算法和擁塞控制。
哪一個可以去掉
擁塞控制可以去掉,因為在帶寬較大,網絡資源豐富時,流量控制已經約束了發送的速率,基本上不會造成網絡擁塞。
11、是什么保證了TCP的 可靠傳輸
TCP 使用確認重傳來實現可靠傳輸:如果一個已經發送的報文段在超時時間內沒有收到確認,那么就重傳這個報文
段。
12、路由協議
自治系統內部的路由選擇:RIP 和 OSPF自治系統間的路由選擇:BGP
1. 內部網關協議 RIP(路由信息協議)
RIP 是一種基於距離向量的路由選擇協議。距離是指跳數,直接相連的路由器跳數為 1。跳數最多為 15,超過 15 表
示不可達。
RIP 按固定的時間間隔僅和相鄰路由器交換自己的路由表,經過若干次交換之后,所有路由器最終會知道到達本自治
系統中任何一個網絡的最短距離和下一跳路由器地址。
RIP 協議實現簡單,開銷小。但是 RIP 能使用的最大距離為 15,限制了網絡的規模。並且當網絡出現故障時,要經
過比較長的時間才能將此消息傳送到所有路由器。
2. 內部網關協議 OSPF
開放最短路徑優先 OSPF,是為了克服 RIP 的缺點而開發出來的。最短路徑優先表示使用了 Dijkstra 提出的最短路徑算法
SPF。所有路由器都具有全網的拓撲結構圖,並且是一致的。相比於 RIP,OSPF 的更新過程收斂的很快。
3. 外部網關協議 BGP
BGP(Border Gateway Protocol,邊界網關協議)
AS 之間的路由選擇很困難,主要是由於:
互聯網規模很大;
各個 AS 內部使用不同的路由選擇協議,無法准確定義路徑的度量;
AS 之間的路由選擇必須考慮有關的策略,比如有些 AS 不願意讓其它 AS 經過。
BGP 只能尋找一條比較好的路由,而不是最佳路由。
每個 AS 都必須配置 BGP 發言人,通過在兩個相鄰 BGP 發言人之間建立 TCP 連接來交換路由信息。
13、擁塞控制,什么時候知道網絡擁塞?
擁塞控制
慢開始算法、擁塞避免、快速重傳、快速恢復
1. 慢開始與擁塞避免
發送的最初執行慢開始,令 cwnd = 1,發送方只能發送 1 個報文段;當收到確認后,將 cwnd 加倍,因此之后發送
方能夠發送的報文段數量為:2、4、8 ...
注意到慢開始每個輪次都將 cwnd 加倍,這樣會讓 cwnd 增長速度非常快,從而使得發送方發送的速度增長速度過
快,網絡擁塞的可能性也就更高。設置一個慢開始門限 ssthresh,當 cwnd >= ssthresh 時,進入擁塞避免,每個輪
次只將 cwnd 加 1。
如果出現了超時,則令 ssthresh = cwnd / 2,然后重新執行慢開始。
2. 快重傳與快恢復
在接收方,要求每次接收到報文段都應該對最后一個已收到的有序報文段進行確認。在發送方,如果收到三個重復確認,那么可以知道下一個報文段丟失,此時執行快重傳,立即重傳下一個報文段。例
如收到三個 M 2 ,則 M 3 丟失,立即重傳 M3 。快恢復指的是發生快重傳之后不必進入慢開始狀態,而是將發送窗口減半,直接開始擁塞避免。
慢開始和快恢復的快慢指的是 cwnd 的設定值,而不是 cwnd 的增長速率。
流量控制:
流量控制是為了控制發送方發送速率,保證接收方來得及接收。通過
滑動窗口機制可以實現這個發送速率的控制,發送窗口大小不能大於接受窗口,動態的改變窗口的大小,從而影響發送方的發送速率。將窗口字段設置為
0,則發送方不能發送數據。可以通過持續計數器和發送探測報文可以打破僵。
什么時候知道網絡擁塞
通過觀察網絡的吞吐量與網絡負載間的關系
如果隨着網絡負載的增加,網絡的吞吐量明顯小於正常的吞吐量,那么網絡就進入輕度擁塞的狀況。
如果網絡得吞吐量隨着網絡負載的增大反而下降,那么網絡就可能進入擁塞狀態。
14、UDP 和 TCP 的區別和特點
用戶數據報協議 UDP(User Datagram Protocol)是無連接的,盡最大可能交付,沒有擁塞控制,面向報文
(對於應用程序傳下來的報文不合並也不拆分,只是添加 UDP 首部),支持一對一、一對多、多對一和多對多
的交互通信。
傳輸控制協議 TCP(Transmission Control Protocol)是面向連接的,提供可靠交付,有流量控制,擁塞控
制,提供全雙工通信,面向字節流(把應用層傳下來的報文看成字節流,把字節流組織成大小不等的數據
塊),每一條 TCP 連接只能是點對點的(一對一)。之所以只能是一對一,我覺得可能是如果支持多播的話,那因為確認應答和超時重傳機制,每次接收方都對發送發的數據進行確認應答,而如果一定時間沒有收到接收方的確認,發送方也需要超時重傳,這樣如果在多播的情況下,如果有一個接收方因為各種原因沒有發送應答信號,可能會影響整個多播網絡的消息傳輸
tcp 和 udp 別適合什么應用?聊天要用什么?
TCP 應用於對
效率要求相對低,但對
准確性要求相對高;或者是有
連接的場景 如:文件傳輸,發送郵件,遠程登錄
UDP 應用於對
效率要求相對高,對
准確性要求相對低的場景,比如:
1. 即時通信(QQ聊天,對數據准確性和丟包要求比較低,但速度必須快);
2、在線視頻(RTSP 速度一定要快,保證視頻連續,但是偶爾花了一個圖像幀,人們還是能接受的)
3、網絡語音電話(VoIP 語音數據包一般比較小,需要高速發送,偶爾斷音或串音也沒有問題)等等
參考:TCP和UDP的區別分析和應用場景
15、HTTP狀態碼
http的狀態碼:
服務器返回的 響應報文 中第一行為狀態行,包含了狀態碼以及原因短語,用來告知客戶端請求的結果。
100:continue,表示到目前位置都很正常,可以繼續請求或者忽略這個回應。
200:OK
204:No content:請求已經成功處理,但是響應不包含主體部分。
206:partial content:返回請求的范圍部分
301:move permanently:永久性重定向,一般是
資源(網頁等)被永久轉移到其它
URL
302:found:臨時性重定向,一般是
資源臨時移動
303:see other:和302類似,但是明確要求用GET
304:not modified;請求首部包含一些條件,不滿足則返回304
307:和302類似,但是明確要求瀏覽器不將POST變為GET
400:bad request:請求報文中存在語法錯誤,多半是前端提交的字段名稱或者字段類型和后台的實體類不一樣,或者前端提交的參數跟后台需要的參數個數不一致,導致無法封裝。
401:unauthorized:表示請求需要有認證信息,如果已經請求過一次了,則說明認證失敗。
403:forbidden:請求被拒絕,
通常原因是服務器上某些文件或目錄設置了權限,客戶端權限不夠
404:not found:
用戶輸入錯誤的鏈接,該鏈接指向的網頁不存在。除此之外,也可以在服務器端拒絕請求且不想說明理由時使用。
405: method not allowed:方法不允許
500: Internal serval error:服務器處理請求時發生錯誤,
服務器內部錯誤(比如瀏覽器代理除了問題,ip,端口不對等)該狀態碼表明服務器端在執行請求時發生了錯誤。也有可能是Web應用存在的bug或某些臨時的故障。
503: server unavarilable:服務器負載過大或者正在維護。
504,Gateway Timeout網關超時 服務器作為網關或代理,未及時從上游服務器接收請求。
16、get 和 post 的區別
以前我看在書上看到的區別的是:
- GET參數通過URL傳遞,而 URL 中傳送的參數是有長度限制的,POST放在Request body中,大小沒有限制。
- GET比POST更不安全,因為參數直接暴露在URL上,所以不能用來傳遞敏感信息。
- 對參數的數據類型,GET只接受ASCII字符,而POST沒有限制。
- GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。
- GET請求參數會被完整保留在瀏覽器歷史記錄里,而POST中的參數不會被保留。
- GET 是冪等的,執行多少遍不影響最終存儲的結果。而
post
每次調用都會創建新的資源。
- GET常用於獲取資源的請求 、 POST常用於修改服務器資源的請求
但是我又看到網上博客說
它們的本質都是 TCP 鏈接,並無區別。但是由於 HTTP 的規定以及瀏覽器/服務器的限制,導致它們在應用過程中可能會有所不同。
get請求冪等性
17、虛擬專用網 VPN
由於 IP 地址的緊缺,一個機構能申請到的 IP 地址數往往遠小於本機構所擁有的主機數。並且一個機構並不需要把所
有的主機接入到外部的互聯網中,機構內的計算機可以使用僅在本機構有效的 IP 地址(專用地址)。
有三個專用地址塊:
10.0.0.0 ~ 10.255.255.255
172.16.0.0 ~ 172.31.255.255
192.168.0.0 ~ 192.168.255.255
VPN 使用公用的互聯網作為本機構各專用網之間的通信載體。專用指機構內的主機只與本機構內的其它主機通信;
虛擬指好像是,而實際上並不是,它有經過公用的互聯網。
網絡地址轉換 NAT
專用網內部的主機使用本地 IP 地址又想和互聯網上的主機通信時,可以使用 NAT 來將本地 IP 轉換為全球 IP
18、Socket
(1) 服務端如何起一個Socket服務
(2) 如何限制Socket的最大連接數-設定一個集合和count變量 -這個集合用什么數據結構比較好
(3) Client發起連接請求是怎樣的,何時才能發起請求
19、session 和 cookie 的區別:
HTTP是一種無狀態的協議,為了分辨連接是誰發起的,需自己去解決這個問題。不然有些情況下即使是同一個網站每打開一個頁面也都要登錄一下。而Session和Cookie就是為解決這個問題而提出來的兩個機制。
區別:
- 存儲數據量方面:session 能夠存儲任意的 java 對象,cookie 只能存儲 String 類型的對象且單個cookie 能夠保存的數據 <= 4KB,大小限制是因為cookie需要在服務器和瀏覽器之間傳遞,如果大小太大會影響性能
- 一個在客戶端一個在服務端。因Cookie在客戶端所以可以編輯偽造,不是十分安全。所以不是很隱私的數據才會存在cookie中
- Session過多時會消耗服務器資源,大型網站會有專門Session服務器,Cookie存在客戶端沒問題。比較隱私的數據都存在session中
- 域的支持范圍不一樣,Cookie支持跨域訪問,但是 Session 不支持跨域訪問。比方說a.com的Cookie在a.com下都能用,而www.a.com的Session在api.a.com下都不能用,解決這個問題的辦法是JSONP或者跨域資源共享/
20、DNS 域名系統(Domain Name System)
把網址轉換成 ip 地址
域名服務器的結構:
根域名服務器,頂級域名服務器, 權限域名服務器,本地域名服務器
域名查詢的方式:
1. 迭代查詢
2. 遞歸查詢