【雜談】從CGI到Servlet

貓毛·波拿巴發表於2018-10-13

訪問伺服器的靜態頁面

  每個Web伺服器都執行著一個HTTP服務軟體,用於響應web瀏覽器的請求,返回客戶想要的頁面。HTTP伺服器都會有一個資料夾用於放置相關的頁面檔案,預設是  /user/local/apache/htdocs 。例如,伺服器的域名叫 example.com。那客戶端瀏覽器訪問http://example.com/index.html   就是訪問伺服器上的HTTP伺服器(URL如果沒有指定埠,就是訪問80埠,80埠繫結的是HTTP服務,80埠是預設對外開啟的),那HTTP伺服器就會重定向到 /user/local/apache/htdocs 資料夾,並查詢是否有index.html 檔案,有則返回,沒有則返回錯誤報文。

訪問伺服器的動態頁面

  伺服器只提供靜態頁面還不夠,客戶端想要更多的服務,比如動態的頁面(頁面上顯示當前使用者資訊等等),或者修改資料庫內容。這時候,服務端就不能單純地對映並返回檔案來實現了,這時候就需要有可執行的指令碼程式來對頁面進行更改,或者其他操作。就拿動態頁面來說,客戶端瀏覽器訪問 http://example.com/home?name=randy 這裡使用者帶上了自己的使用者名稱,希望訪問的主頁右上角能顯示自己的名字。這裡 home 通過對映到一個CGI程式,並執行。該程式通過標準I/O流,解析HTTP報文,獲取到了請求引數,並通過程式生成對應的HTML檔案,在通過標準I/O流,將檔案返回給請求客戶。

注:CGI (Common Gateway Interface)通用閘道器介面,CGI程式常見的由Perl,Python,C,C++  或者任何可利用標準I/O流的語言。

Java的一種想法

  一開始,人們想最理想的方式就是完全基於Java的實現方案, servlets <=> applets 。即

  客戶端用applet校驗併傳送資料,

  服務端用servlet接收並處理資料。

  就連這名稱都是一對。

  但是,並非所有瀏覽器都支援Java。這樣就帶來一個問題,那就是你搭建的網站,只有部分瀏覽能夠訪問,而且需要安裝對應程式。後來,就把所有的操作都交給伺服器處理,然後把最終生成的網頁發給客戶端瀏覽器。這樣,只要有瀏覽器,就可以訪問對應網站,且不需要安裝任何程式。

Servlet的引入

  Servlet是基於Java的CGI程式框架。首先,因為它是一個框架,所以就可以省去很多底層編寫的工作。又因為是用Java實現的,Java程式執行於Java虛擬機器,跨平臺性好,便於網站遷移。

Servlet的體系架構

  Servlet容器,如Tomcat,接收所有客戶端請求,如 http://example.com:8080/project/oneServlet,根據"project"找到對應的專案(tomcat的server.xml儲存專案對映資訊),再根據"oneServlet"找到對應的Servlet(Web專案的web.xml儲存Servlet對映資訊),然後呼叫該Servlet物件的service()方法。service方法會根據請求的方式,委派給doGet、doPost、doDelete等方法進行處理。

  注:Servlet的多數內容由容器實現,如Session的儲存和獲取,Tomcat實現內容在其子目錄lib下的catalina相關包內。

Servlet的持久化

  Servlet會儲存其變數域的值,使其在多個請求之間保留相應變數值。Servlet容器會持久化Servlet物件。至於什麼時候重新整理,尚未考察,應該是在每次service()方法返回之後。

如果是CGI程式,則需要自己手動將資料寫入到磁碟,這也是Servlet的優點之一。

Servlet的頁面生成與JSP

  如果單純用Servlet生成頁面,那麼將會非常痛苦,因為這樣程式碼裡就會摻雜大量的 換行符、轉義標識、“+”符號,字串的構建以及程式碼閱讀都非常困難。後來就有了JSP檔案,整合了HTML和Java程式碼。使得檔案內可以直接抒寫HTML程式碼,而不需要用字串拼接。也可以用有特殊標籤包圍的Java程式碼。(實際上JSP就是Servlet,它會被容器內會被轉換成Servlet的.java檔案,然後在編譯成.class檔案)但是,JSP還有問題沒解決,那就是,負責維護JSP的開發人員必須既懂HTML又懂Java。而且兩種語言混合在一起(一種程式語言,一種標記語言),在加上各種標籤庫,看起來比較吃力。

偏題內容:頁面渲染的位置

  早期是伺服器把網頁完全渲染好後,然後發給客戶端瀏覽器,瀏覽器負責顯示就可以了。但是這樣的話,伺服器的壓力就比較大,而且響應時間會比較長,客戶端要等到服務端把頁面完全渲染好後才能看見頁面。後來的做法,是這樣的,伺服器先把有基本內容的網頁檔案發給客戶端瀏覽器,然後瀏覽器再非同步地請求(如通過Ajax)獲取資料,然後根據獲取到的資料對網頁進行渲染(例如獲取到一個陣列物件,然後根據陣列生成一個表格,顯示資料)。這樣,伺服器的壓力就小多了,而且客戶端也能較早地看見頁面(尚不完整,部分資料還未載入)。

  那瀏覽器有是怎麼就知道發非同步請求呢?是這樣的,用javascript寫全域性程式碼,或者覆蓋Vue物件中的created函式,這樣瀏覽器一收到網頁檔案並載入的時候,這些JS程式碼就會被觸發執行。

Servlet與多執行緒

  Servlet容器維護有一個執行緒池用於分派處理客戶端的請求。所以,多個請求可以併發,甚至並行處理。

Servlet處理會話(Session)—— 利用Cookie

  HTTP是無狀態協議,多次請求中,單純靠HTTP協議,我們並不能辨別其是否是同一個人。但是,有處理會話的需求(例如購物車的實現需求),這時候就要追蹤會話。追蹤會話的方式有很多,最常見的是持久化Cookie。

Session-Cookie機制:Cookie是伺服器發給客戶端的一小段資訊(包含Session的唯一識別符號),瀏覽器收到Cookie後,把它寫入到磁碟持久化。無論何時,如果訪問與某個Cookie相關聯的URL時,請求中就會帶上這個Cookie。Servlet如果想要獲取本次請求的會話,就呼叫HttpServletRequest.getSession()獲取。getSession()方法獲取Session的實現方式尚未考察,但猜測應該是根據請求中的Cookie,從Servlet容器內檢索對應的Session。

Session的存活時間

  Session即會話的存活時間預設是30min,但是具體情況,得看對應的Servlet容器。每個容器的會話存活時間都不盡相同。

Session的用途

  Session物件的作用就是捕捉客戶端與服務端互動的有用資料,如前面提到的購物車資訊,還有就是Session物件可以用來儲存認證資訊(即是否已登入),這樣多次請求中,Servlet只要確認"是否登入"狀態即可,而不需要使用者每次請求都登入。

 

相關文章