Http權威指南筆記(五)——Web服務器

前面四篇屬於《HTTP權威指南》第一部分內容。接下來幾篇進入第二部分內容的學習,首先介紹Web服務器。
Web服務器就是整個萬維網的骨幹,廣義上來說Web服務器既可以用來表示Web服務器的軟件,也可以用來表示提供Web頁面的特定設備和計算機。我們在網絡上獲取的所以資源,都需要有服務器來保存和提供。另外需要說明的是本篇中對於Web服務器的配置說明是基於Apache Web服務器的。

1 Web服務器的類型

Web 服務器有着不同的風格、形狀和尺寸。有普通的 10 行 Perl 腳本的 Web 服務器、50MB 的安全商用引擎以及極小的卡上服務器。但不管功能有何差異,所有的 Web 服務器都能夠接收請求資源的 HTTP 請求,將內容回送給客戶端。
Web服務器邏輯實現了HTTP協議,負責管理其提供的資源和提供對服務器的配置、控制等功能。Web服務器會和操作系統協作共同實現TCP連接。底層的操作系統會提供TCP/IP網絡支持,並向上提供TCP的相關接口給Web服務器進行調用。
要實現一個Web服務器,我們可以在標準的計算機上安裝Web服務器軟件,或者直接購買一臺已經安裝和配置了Web服務器軟件的計算機。除了這些外,現在還可以在一些嵌入式設備中嵌入Web服務器。下面對着三種實現方式進行簡單的說明:

  1. 通用軟件Web服務器
    通用軟件 Web 服務器都運行在標準的、有網絡功能的計算機系統上。可供選擇的也非常多,免費的如Apache基金提供的軟件,付費的如微軟的Web服務器。目前來看,免費的Web服務器軟件已經相當不錯了,而且使用和配置也很方便,很多中小型公司都會使用免費開源的Web服務器軟件。比如現在非常流行的Tomcat,如果你想搭建一個Web服務器進程試用、調試等,這個是非常不錯的選擇。
  2. Web服務器設備
    Web 服務器設備(Web server appliance)是預先打包好的軟硬件解決方案。廠商會在他們選擇的計算機平臺上預先安裝好軟件服務器,並將軟件配置好。這個接觸不多,有興趣的可以自行了解一下。
  3. 嵌入式Web服務器
    嵌入式服務器(embeded server)是要嵌入到消費類產品(比如打印機或家用設備)中去的小型 Web 服務器。嵌入式 Web 服務器允許用戶通過便捷的 Web 瀏覽器接口來管理其消費者設備。

2 Web服務器需要處理的事情

如果用一張圖裏描述Web服務器需要做的事情,如下:
Web服務器響應過程
從圖中我們可以看到,Web服務器主要需要處理以下幾項事情:

  1. 建立連接——接受客戶端的連接請求
  2. 接受請求——從連接中讀取一條HTTP請求報文
  3. 處理請求——根據HTTP規範解析請求後,根據請求做出動作
  4. 訪問資源——解析完請求報文後,根據報文訪問指定的資源
  5. 構建響應——處理好資源後,根據HTTP規範構建響應
  6. 發送響應——將構建好的響應發送給客戶端
  7. 記錄日誌——根據需要,將該次處理有關內容記錄到日誌文件中
    下面就分別對這幾點進行簡單描述:

2.1 接受客戶端連接

一般客戶端想要發起一個請求,除非已經建立持久連接,否則就會新建立一個到服務器的連接。服務器這端就需要接受客戶端連接。該過程中,主要處理一下幾件事情:
1. 處理新連接
當新連接請求到來的時候,服務器一般會先從TCP連接中解析出客戶端IP地址。需要判斷是否接受該條連接(如:判斷客戶端IP地址是否是認證過的),如果不接受,可以拒絕或者關閉連接。如果接受,一般就會將連接添加到連接列表,並做好該連接上數據的監聽,做好傳輸的準備。
2. 客戶端主機名識別
服務器解析數客戶端IP地址後,可以通過“反向DNS”對IP地址進行解析,得到客戶端的主機名。但是該過程是一個比較耗時的操作,所以如果不需要此項內容,一般會將主機名解析禁止掉,以便提高服務器處理速度。比如:可以用配置指令 HostnameLookups 來控制 Apache 的主機查找功能。
4. 通過ident確定客戶端用戶
有些 Web 服務器還支持 IETF 的 ident 協議。服務器可以通過 ident 協議找到發起 HTTP 連接的用戶名。這些信息對 Web 服務器的日誌記錄特別有用——流行的通用日誌格式(Common Log Format)的第二個字段中就包含了每條 HTTP 請求的 ident 用戶名。
如果客戶端支持ident協議,通常會在113端口上做ident監聽。下圖展示了ident協議是如何工作的:
ident協議
雖然ident協議可以幫助我們獲取客戶端更多信息,但是實際操作中,一般ident都不能很好的提供服務,因爲:一般客戶端並不支持ident協議,很多防火牆不允許ident流量流入,同時該協議不是一個安全的協議,很容易被人僞造,同時這個也涉及到個人隱私問題。
在Apache服務器中,可以通過IdentityCheck on 指令告知 Apache Web 服務器使用 ident 查找功能。

2.2 接收請求報文

上一步的連接完成,做好連接上的數據監聽工作後,待客戶端將HTTP報文發送過來,服務器這邊需要接收該報文(PS:原書當中將報文的初步解析也放在該階段,個人理解報文解析應該放在請求處理階段,所以這裏暫不提解析的事情)。
這裏接收報文的時候,效率也是很重要的,高性能的 Web 服務器能夠同時支持數千條連接。不同的 Web 服務器結構會以不同的方式爲請求服務(Web的訪問響應模型,或者也叫連接的輸入/輸出處理結構)。目前來說主要有如下四種方式:
Web訪問響應模型
在介紹的時候,先做個說明,上圖中都是以線程爲單位進行說明的,個人理解此處應該以進程爲單位,所以下面的描述中以進程爲單位進行說明。

  1. 單進程I/O結構(圖a)
    Web服務器使用一個進程串行的方式進行請求處理,一次只接收一個請求,這種方式幾乎已經被淘汰,效率太低。
  2. 多進程I/O結構(圖b)
    Web服務器啓用多個進程對請求進行處理,同一時間,每個進程都能單獨處理一個請求。但是一般服務器會對進程做一個最大數量的限制,以防止資源耗盡的情況。
  3. 複用I/O結構(圖c)
    原書對此處表述個人不是非常理解,目前個人理解的是利用“連接池”技術。在一個進程中,開啓多個線程,每個線程處理一個請求,當一個線程的請求處理完成後,不立即銷燬,而是放回到“連接池”中,等待下一個需要處理的請求。所以在實現方式上利用多線程和“線程池”技術。
  4. 複用的多進程I/O結構(圖d)
    這個其實也就是將多進程,多線程(線程池)技術綜合使用,達到有個多進程對請求進行處理,同時每個進程裏面又維護了一個“線程池”真正對請求進行處理。

2.3 處理請求

這裏將原書中的報文解析放在該階段了,所以此階段的內容就是對報文按照HTTP規範進行解析,一般都會根據報文的三部分請求行、請求頭(本書中所說的首部)、請求體進行封裝處理,以便後續可以很快速的訪問所需內容。解析完報文後,就會根據其內容,產生不同的動作,這裏就不做詳細接收了,後面大部分的內容就是在介紹怎麼處理的問題。

2.4 對資源進行映射訪問

Web服務器本質上就是個資源服務器,主要功能就是對外提供資源,在 Web 服務器將內容傳送給客戶端之前,要將請求報文中的 URI 映射爲 Web 服務 器上適當的內容或內容生成器。

2.4.1 docroot

Web服務器有多種資源映射類型,最簡單的便是直接將URI中的路徑映射爲Web服務器文件系統中的路徑。這種映射方式,通常會有一個專門用於存放資源的文件夾。這個文件夾通常被稱爲docroot(或者 document root)。在映射的時候,解析出URI中的路勁,將其作爲相對路徑附在該docroot目錄路徑後面。如:
docroot
上圖中請求的URI中的路徑爲/specials/saw-blade.gif,該Web服務器的docroot目錄爲路徑爲/usr/local/httpd/files。通過映射後,最終Web服務器就會到/usr/local/httpd/files/specials/saw-blade.gif路徑下去獲取資源。
通常我們實際操作中還會遇到一個Web服務器有多個Web站點的情況。這個時候如果我們URI中的路徑相同,如都爲:/index.html,這個時候Web服務器會根據HOST或者URI中的IP來進行區別,找到不同的docroot,最終將請求資源映射到正確的路徑。
docroot的配置,每個Web服務器都有自己的一套規則,這裏以Apache爲例,如下:

<VirtualHost www.joes-hardware.com>
  ServerName www.joes-hardware.com
  DocumentRoot /docs/joe
  TransferLog /logs/joe.access_log
  ErrorLog /logs/joe.error_log
</VirtualHost>
 
<VirtualHost www.marys-antiques.com>
  ServerName www.marys-antiques.com
  DocumentRoot /docs/mary
  TransferLog /logs/mary.access_log
  ErrorLog /logs/mary.error_log
</VirtualHost>

上面就在同一個Web服務器張部署了兩個Web站點,並且分別設置了不同的docroot路徑。

2.4.2 目錄列表

Web服務器除了可以接收指向具體資源的URL請求外,還能處理指向目錄的URL的請求。當Web服務器收到一個指向目錄的URL請求後,一般採取如下幾種方式進行處理:

  • 直接返回一個錯誤信息
  • 在當前目錄下找指定的索引文件
  • 掃描目錄,尋找一個包含該目錄的內容的HTML文件
    大多數Web服務器默認處理方式,會在在當前目錄下找一個index.html或者index.htm的文件,如果找不到會返回一個404錯誤。當然,大部分Web服務器都是支持我們自己對目錄請求的默認尋找文件進行配置的,如Apache的DirectoryIndex指令:
    DirectoryIndex index.html index.htm home.html home.htm index.cgi
    有了該條配置,服務器就會默認會去依次尋找上述列出的所有文件,直到找到一個並返回內容,如果搜索完畢也找不到,也會返回一個錯誤。

2.4.3 動態資源的映射

上面介紹的映射都是靜態映射,即將URL路徑映射到指定的靜態文件。除了靜態映射,Web服務器還支持動態映射——將URL路徑映射到按需生成內容的程序上。下圖展示了一個Web服務器既提供靜態資源,也提供動態資源:
Web動態資源
目前Web服務器大多數時候都是在提供動態資源,常用的動態動態內容支持機制有微軟的Active Server Page和Java Servlet。

2.4.4 服務器端包含項

此處個人理解通常就是指我們的模板文件,比如現在比較流行的FeeMarker,Thymeleaf。都可以先提供一個HTML模板文件,然後根據動態查詢到的內容,進行替換或者處理後,再將內容返回給客戶端。

2.4.5 訪問控制

在對資源映射的時候,還可以做訪問控制。如:指定某些資源是需要登錄用戶才能訪問,某些資源是需要付費用戶才能訪問等。詳細內容,後面會有專門的章節進行介紹。

2.5 構建響應

一旦Web服務器已經找到需要的資源,就需要使用該資源構建響應報文(響應行,響應頭,相應體)。通常來說,響應報文應該含有一下幾項:

  • Content-type首部——用於描述相應體內容的MIME類型
  • Content-length首部——用於描述相應體內容的長度
  • 響應體中的具體內容
    這裏MEME類型的獲取一般有如下幾種方式:
  1. 通過文件的擴展名來進行判斷,這個是最常用的方式
  2. 通過掃描資源的內容然後和移植模板表進行對比匹配,以獲取資源的MIME類型,這種方式可以用於文件沒有擴展名的時候,但是效率比較低下
  3. 直接將某個資源強制指定爲某個MIME類型,無論其內容是什麼
  4. 可以通過Web服務器配置,使其與用戶協商使用哪種MIME類型最好,該種方式後續會專門的說明。

2.5.1 重定向

有時候Web服務器並不是總是成功返回所需資源內容的報文。有時候Web服務器會返回一個重定向的報文,響應碼是3XX,同時包含一個Location首部,其內容是所請求資源的新URL地址或者優選URL地址。一般重定向主要是用於以下幾種情況:

  • 永久搬離資源
    Web服務重新整理資源,該資源的搬離了原來的位置,或者被重新命名了。這個時候如果客戶端用以前的URL地址進行訪問的時候,服務器可以告訴客戶端,該資源已經搬離或重名了,並且告訴客戶端新的URL地址。這種情況一般使用301狀態碼,讓客戶端以後要想訪問該資源都請訪問的URL。
  • 臨時搬離資源
    如果資源只是臨時搬離或者重命名,不久的將來還會還原回去。這個時候也是通過重定向告訴客戶端,我們臨時調整了下新URL地址,但是後面還會還原回去,所以這次你先臨時到新URL地址獲取資源,後面還是按照之前的URL進行訪問。這種情況一般使用303或者307狀態碼,至於這兩者的區別,前面Http權威指南筆記(三)——HTTP報文已經分析過了,這裏不在贅述。
  • URL增強
    某些時候,訪問一個資源可能需要一些額外信息,但是客戶的請求的URL沒有這些信息,服務器這邊又能夠自動填充這些信息。這個時候當客戶端發起請求後,服務器可以利用重定向,將需要填充的信息補充到URL中,然後將完整的URL放入Location首部。客戶端收到重定向返回報文後,就會自動用填充好信息的URL進行重新訪問了。同樣這種情況一般也是用303或307狀態碼
  • 負載均衡
    如果一個超載的服務器收到一條請求,服務器可以將客戶端重定向到一個負載不太重的服務器上去。這種情況一般也是使用 303 和或307 狀態碼。
  • 服務器關聯
    Web 服務器上可能會有某些用戶的本地信息;服務器可以將客戶端重定向到包含了那個客戶端信息的服務器上去,一是一般使用303或者307狀態碼。
  • 規範目錄名稱
    客戶端請求的 URI 是一個不帶尾部斜線的目錄名時,大多數 Web 服務器都會將客戶端重定向到一個加了斜線的 URI 上,這樣相對鏈接就可以正常工作了。

2.6 發送響應和記錄日誌

通過上面的步驟,將響應構建好之後,就需要將響應發送給客戶端。發送響應的時候,和接收數據一樣,因爲同事可能存在多個到客戶端的連接,某些在接收數據,某些在發送數據,某些是空閒的,我們需要記錄連接的狀態,對於非持久連接,發送完響應數據後,可以關閉自己這一端的連接。對於持久連接,可能需要仍然保持連接的打開狀態,這種情況,特別注意Content-length字段的正確性。
發送完響應數據後,最後我們通過日誌系統,往日誌文件中寫入日誌,用於記錄和描述當前事務的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章