Web服務器是如何進行工作的
====================文章摘自《HTTP權威指南》======================
1、 建立連接—接收一個客戶端的連接,或者如果不希望與這個客戶端建立連接,就將其關閉;
2、 接收請求—從網絡中讀取一條HTTP請求報文;
3、 處理請求—對請求報文進行解釋,並采取行動;
4、 訪問資源—訪問報文中指定的資源;
5、 構建響應—創建帶有正確首部的HTTP響應報文;
6、 發送響應—將響應回送給客戶端;
7、 記錄事務處理過程—將與已經完成事務有關內容記錄在一個日志文件中;

1、 接收客戶端連接
(1)、
客戶端請求一條到服務器的TCP連接時,Web服務器會建立連接,判斷連接的另一端是哪個客戶端,從TCP連接中將IP地址解析出來。一旦新連接建立起來並被接受,服務器就會將新連接添加到其現存的Web服務器連接列表中,做好監視連接上數據傳輸的准備。
Web服務器可以隨時拒絕或立即關閉任意一條連接。有些Web服務器會因為客戶端IP地址或主機名是未認證的,或者因為它是已知的惡意客戶端而關閉連接。Web服務器也可以使用其他識別技術。
(2)、客戶端主機名識別
可以用“反向DNS”對大部分Web服務器進行配置,以便將客戶端IP地址轉換成客戶端主機名。Web服務器可以將客戶端主機名用於詳細的訪問控制和日志記錄。但要注意的事,主機名查找可能會花費很長的時間,這樣會降低Web事務處理的速度。很多大容量Web服務器要么會禁止主機名解析,要么只允許對特定的內容進行解析。
(3)、通過ident確定客戶端用戶
有些Web服務器還支持IETFident的協議。服務器可以通過ident協議找到發起HTTP連接的用戶名,這些信息對Web服務器的日志記錄特別有用—流行的通用日志格式(Common Log Format)的第二個字段就包含了每條HTTP請求的ident用戶名。
如果客戶端支持ident協議,就在TCP端口113上監聽ident請求。圖5-4說明了ident協議是如何工作的。在圖5-4a中,客戶端打開了一條http連接。然后服務器打開自己到客戶端ident服務器端口(113)的連接,發送一條簡單的請求,詢問與(由客戶端和服務器端口號指定的)新連接相對應的用戶名,並從客戶端解析出包含用戶名的響應。
2、 接收請求報文
連接上有請求報文達到時,web服務器會從網絡連接中讀取數據,並將請求報文中的內容解析出來(見圖5-5)
解析請求報文時,web服務器會:
A、 解析請求行,查找請求方法、指定的資源標識符(URI)以及版本號,各項之間由一個空格分隔,並已一個回車換行(CRLF)序列作為行的結束;
B、 讀取以CRLF截尾的報文首部;
C、 檢測到以CRLF結尾的、標識首部結尾的空行(如果有的話);
D、 如果有的話(長度由content-Length首部指定),讀取請求主題;
解析請求報文時,web服務器會不定期從網絡上接收輸入數據。網絡連接可能隨時都會出現延遲。Web服務器需要從網絡中讀取數據,將部分報文數據臨時存儲在內存中,直到收到足以解析的數據並理解其意義為止。
(1)、報文的內部表示法
有些web服務器還會用便於進行報文操作的內部數據結構來存儲請求報文。比如,數據結構中可能包含有指向請求報文中各個片段的指針及其長度,這樣就可以將這些首部放在一個快速查詢表中,以便快速訪問特定首部的具體值了。
(2)、連接的輸入\輸出處理結構
高性能的web服務器能夠同時指出數千條連接。這些連接使得服務器可以與世界各地的客戶端進行通信,每個客戶端都想服務器打開了一條或多條連接。某些連接可能在向服務器快速的發送請求,而其他一些連接可能在慢慢發送,或不經常發送請求,還有一些可能是空閑的,安靜的等待着將來可能出現的動作。
因為請求可能在任意時間到達,所以web服務器會不停的觀察有無新的請求。不同的web服務器結果會以不同的方式為請求服務,見圖5-7所示。
A、 單線程web服務器(5-7a)
單線程的web服務器一次只處理一個請求,直到其完成為止。一個事務處理結束后,采取處理下一條請求。這種結構易於實現,但在處理過程中,所有其他鏈接都會被忽略。這樣會造成嚴重的性能問題,只適用於低負荷的服務器,以及type-o-serve這樣的診斷工具。
B、 多進程及多線程web服務器(5-7b)
多進程和多線程服務器用多個進程或更高效的線程同時對請求進行處理。可以根據需要創建,或者預先創建一些線程/進程。有些服務器會為每條連接分配一個線程/進程,但當服務器同時處理成百上千甚至數以萬計的連接時,需要的進程或線程的數量可能會消耗太多的內存和系統資源。因此很多多線程web服務器都會對線程/進程的最大數量進行限制。
C、 復用I/O的服務器
為了支持大量的連接,很多web服務器都采用的復用結構。在復用結構中,要同時監視所有連接上的活動。當連接的狀態發生變化時(比如,有數據可用,或出現錯誤時),就對那條連接進行少量的處理;處理結束之后,將連接返回到開放連接列表中,等待下一次狀態變化。只有在有事情可做時才會對連接進行處理;在空閑連接上等待的並不會綁定線程和進程。
D、 復用的多線程web服務器(5-7d)
有些系統會將多線程和復用功能結合在一起,以利用計算機平台上的多個CPU。多個線程(通常是一個物理處理器)中的每一個都在觀察打開的連接(或打開的連接中的一個子集),並對每條連接執行少量的任務。

3、 處理請求
一旦web服務器收到了請求,就可以根據方法、資源、首部和可選的主體部分來對請求進行處理了。
有些方法(比如POST)要求請求報文中必須帶有實體主體部分的數據。其他一些方法(OPTIONS)允許有請求的主體部分,也允許沒有。少數方法(GET)禁止在請求報文中包含實體的主體數據。
4、 對資源的映射和訪問
Web服務器是資源服務器。他們負責發送預先創建好的內容,比如HTML頁面或者JPEG圖片,以及運行在web服務器上的資源生成程序鎖產生的動態內容。
在web服務器將內容傳送給客戶端之前,要將請求報文中的URI映射為web服務器上適當的內容或內容生成器,以識別出內容的源頭。
(1)、docroot
Web服務器支持各種不同類型的資源映射,但最簡單的資源映射形式就是請求URI作為名字來訪問web服務器文件系統中的文件。通常web服務器的文件系統會有一個特殊的文件夾專門用於存放web內容。這個文件夾被稱為文件根目錄(document root或docroot)。 Web服務器從請求報文中獲取URI,並將其附加在文檔根目錄的后面
在圖5-8中,有一條對/specials/saw-blade.gif的請求達到。在這個例子中,web服務器的文檔根目錄為/usr/local/httpd/files.web服務器會返回文件/usr/local/httpd/files/specials/saw-blade.gif。
在配置文件httpd.conf中添加一個documentroot行就可以為Apache web服務器設置文檔的根目錄了。Documentroot /usr/local/httpd/files
服務器需要注意,不能讓相對URL推到docroot之外,將文件系統的其余部分暴露出來。比如,大多數成熟的web服務器都不允許這樣的URI看到joe五金商店文檔根目錄上一級的文件:http://www.joe-hardware.com/../

A、 虛擬托管的docroot
虛擬托管的web服務器會在同一台web服務器上提供多個web站點,每個站點在服務器上都會有自己獨有的文檔根目錄。虛擬托管web服務器會根據URI或Host首部的IP地址或者主機名來識別要使用的正確文檔根目錄。通過這種方式,即使請求URI完成相同,托管在同一web服務器的兩個web站點也可以擁有完全不同的內容了。
圖5-9中的服務器托管了兩個站點,www.joes-hardware.com和www.marys-antiques.com。服務器可以通過HTTP的host首部,或根據不同的IP地址來區分不同的web站點。
a、當請求A達到時,服務器或獲取文件/docs/joe/index.html.
b、當請求B達到時,服務器會獲取文件/docs/mary/index.html.

對大多數服務器來說,配置虛擬托管的文檔根目錄是很簡單的。對常見的Apache web服務器來說,需要為每個虛擬的web站點配置一個Vitualhost塊,而且每個虛擬服務器都要包含documentroot。

(2)、目錄列表
Web服務器可以接收對目錄URL的請求,其路徑可以解析為一個目錄,而不是文件。我們可以對大多數服務器進行配置,使其在客戶端請求URL時采取不同的動作。
—返回一個錯誤
—不返回目錄,返回一個特殊的默認的“索引文件”
—掃描目錄,返回一個包含目錄內容的HTML頁面
大多數web服務器都會去查找目錄中一個名為index.html或index.htm的文件來代表此目錄。如果用戶請求的是一個目錄的URL,而且這個目錄有一個名為index.html(index.htm)的文件,服務器就會返回那個文件的內容。
(3)、動態內容資源的映射
Web服務器還可以將URl映射為動態資源——也就是說,映射到按需動態生成內容的程序上去(圖5-11)。實際上,有一個大類為應用程序服務器的web服務器會將web服務器連接到復雜的后端應用程序上去。Web服務器要能夠分辨出資源什么時候是動態的,動態內容生成程序位於何處,以及如何運行那個程序。大多數web服務器都提供了一些基本的機制以識別和映射動態資源。
Apache服務器允許用戶將URI路徑名映射為可執行文件目錄。服務器收到一條帶有可執行路徑組件的對URI的請求時,會試着去執行響應服務器目錄中的程序。例如,下列Apache配置指令就表明所有路徑以/cgi-bin/開頭的URI都應該執行在目錄/usr/local/etc/httpd/cgi-programs/中找到相應的文件。
ScriptAlias/cgi-bin/ /usr/local/etc/httpd/cgi-programs/
Apache還允許用戶用一個特殊的擴展文件名來標識可執行文件。通過這種方式就可以將可執行腳本放置在任意目錄中了。下面的Apache配置指令說明要執行所有以.cgi結尾的web資源:Addhandler cgi-script.cgi
5、 構建響應
一旦Web服務器識別出了資源,就執行請求方法中描述的動作,並返回響應報文。響應報文中包含有響應狀態碼、響應首部,如果生成了響應主體的話,還包括響應主題。
(1)、響應實體
如果事務處理產生了響應實體,就將內容放在響應報文中回送過。如果有響應主體的話,響應報文中通常包括:
描述了響應主體MIME類型的content-type首部;
描述了響應主體長度的content-length首部;
實際報文的主體內容;
(2)、MIME類型
Web服務器要負責確定響應主體的MIME類型。有很多配置服務器的方法可以將MIME類型與資源關聯起來。
A、 MIME類型
Web服務器可以用文件的擴展名來說明MIME類型。Web服務器會為每個資源掃描一個包含了所有擴展名的MIME類型文件,以確定其MIME類型。這種基於擴展名的類型相關是最常見的。
B、 魔法分類
Apache web服務器可以掃描每個資源的內容,將其與一個已知的模式表(被稱為魔法文件)進行匹配,以決定每個文件的MIME類型。這樣做可能比較慢,但很方便,尤其是文件沒有標准的擴展名的時候。
C、 顯示分類(Explicit typing)
可以對web服務器進行配置,使其不考慮文件的擴展名或內容,強制特定文件或目錄內容擁有某個MIME類型。
D、 類型協商
有些web服務器經過配置,可以以多種文檔格式來存儲資源。在這種情況下,可以配置web服務器,使其可以通過與用戶協商來決定使用哪種格式(及相關的MIME類型)“最好”。
(3)、重定向
Web服務器有時會返回重定向響應而不是成功的報文。Web服務器可以將瀏覽器重定向到其他地方來執行請求。重定向響應由返回碼3XX說明。Location響應首部包含了內容的新地址或優選地址的URI。重定向可用於下列情況。
A、 永久刪除的資源
資源可能已經被移動了新的位置,或者被重新命名,有了一個新的URL。Web服務器可以告訴客戶端資源已經被重新命名了,這樣客戶端就可以在從新地址獲取資源之前,更新書簽之類的信息了。
B、 臨時刪除的資源
C、 URL增強
服務器通常用重定向來重寫URL,往往用於嵌入上下文。當請求到達時,服務器會生成一個新的包含了嵌入式狀態信息的URL,並將用戶重定向到這個新的URL上去。客戶度會跟隨這個重定向信息,重新發起請求,但這次請求會包含完整的、經過狀態增強的URL。這是在事務間維護狀態的有效方式。
D、 負載均衡
E、 服務器關聯
Web服務器上可能會有某些用戶的本地信息;服務器可以將客戶端重定向到包含了那個客戶端信息的服務器上去。
F、 規范目錄名稱
客戶端請求的URI是一個不帶尾部斜杠的目錄名時,大多數web服務器都會將客戶端重定向到一個加了斜杠的URI上,這樣相對連接就可以正常工作了。
6、 發送響應
Web服務器通過連接發送數據時也會面臨與接收數據一樣的問題。服務器可能有很多條到各個客戶端的連接,有些是空閑的,有些在向服務器發送數據,還有一些在向客戶端回送響應數據。
服務器要記錄連接的狀態,還要特別注意對持久連接的處理。對非持久連接而言,服務器應該在發送了整條報文之后,關閉自己這一段的連接。
對持久連接來說,連接仍可能保持打開狀態嗎,在這種情況下,服務器要特別小心,要正確的計算content-length首部,不然客戶端就無法知道響應什么是時候結束了。
7、 記錄日志
最后,當事務結束時,web服務器會在日志文件中添加一個條目,來描述已執行的事務。大多數web服務器都提供了集中日志配置格式。
