目前,市場上流行有很多web服務器軟件,每種服務器都有自己的特點。我們在開發的過程中,經常要和它們打交道,所以了解它們的工作原理也是很重要的。
幾款比較流行的服務器
它們會做些什么?
第三篇中有這樣的一張圖片,它演示了客戶端和服務器在發起事務時它們需要做的幾個事情。
這里就詳細地談談服務器在運行過程中會做什么。
首先服務器在完全運行起來之后,客戶端就可以向服務器發起連接了(關於這個部分,大家可以看第三篇筆記)。現在的web服務器大多數都是多線程服務器了,一般在服務器上配置連接池,限制連接的數量,可以大大減輕服務器的連接壓力,以保證網絡服務的質量。
在這個階段,服務器也會判斷客戶端的身份,比如一些有惡意行為的IP地址,服務器會拒絕建立連接。
接下來,服務器就會開始接受客戶端發出的報文並解析它們(關於報文可以看第四篇筆記)。服務器首先會讀取報文的起始行。從它請求的方法中以確定這個請求需要給予什么樣子的響應,在這之后,服務器就會去讀取uri,確定資源的地址,最后在這行信息中檢測客戶端使用的http版本,以確定首部的一些信息解讀的方式。之后就是讀取各行的信息,直到檢測到以CRLF( Carriage-Return Line-Feed 回車換行)結束的標識。在這之后服務器就會對請求開始處理了,比如像post中的一些數據傳遞到程序中。
此時,服務器要開始很重要的步驟了,找到客戶端希望得到的資源,開始構建一個特別的內容給客戶端,這些都是程序處理的部分了。當然,這里請求的資源使用路徑都是服務器上的虛擬路徑,不是服務器文件系統上的絕對路徑。這個虛擬路徑恰好把資源封閉在一個固定的路徑中,不讓訪問突破規定范圍。在linux中有一種SELinux的機制,進程只能訪問那些在他的任務中所需要文件。
在確定了要發送的內容之后,服務器會構建一個響應報文並發送它們。這里面通常會包括一個響應主體的MIME類型響應主體的Content-length以及響應主體頁面。發送完畢后,服務器會檢測這是不是一個持久連接,並根據此,決定是不是要關閉連接。
字符編碼
我想凡是做過開發的人一定都遇到過字符編碼亂碼的問題。關於字符編碼的問題非常復雜。其中有一些就和web服務器接收和構建報文有關系。
一個客戶端吧請求報文在發送給服務器時,可以在發送前,在首部通過設置Accept-Charest和Accecpt-Encoding告訴服務器自己期待的字符編碼方式。服務器會根據這條信息給予客戶端最優化的方案。但有時,亂碼依舊。而這些亂碼是從哪里來的呢?
這要從它的歷史說起了,最早的ASCII碼並不支持中文,為了滿足我們國家的需要,有人對ANSi(ASCII的擴充)碼進行了擴充,制作了GB2312,后來發現GB2312不能顯示一些生僻的字,於是gbk編碼就誕生了,在這之后,有進行了幾次擴展。
但是在ANSi編碼下,同一個編碼值,在不同的編碼體系里代表着不同的字,這就是意味着不同國家的人相互訪問網站的時候,由於不同的編碼,我們就會看見不同的內容(大部分都是不知所雲的亂碼)。
后來有了Unicode編碼,每個符號對應一個唯一的編碼,亂碼問題就不存在了。但是這樣做這個庫就非常龐大,UTF-8可以根據不同的符號自動選擇編碼的長短,這樣又一次提高了字符編碼的效率。
所以,utf-8應該是我們最好的選擇。如果我們使用GB2312,我們在URL傳遞中文數據時,就會變成一堆符號和數字,而我們采用utf-8時,就不會有這個問題。有時候,我們很少注意,自己在開發時,頁面本身的字符編碼格式。所以很多不同字符編碼定義,就讓服務器不知所措了,有時候數據庫的字符編碼和接收的字符編碼又是不同的,這里又一次造成了編碼的不和諧。