前言
簡單的邏輯的處理。此次分析的是Servlet對HTTP請求的處理和對錶單的處理。
下面HTTP的通信機制參考此篇文章:
http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html
HTTP通信機制
在前面的學習中知道HTTP是一套網絡通信協議,而且它是一種無狀態的協議。這裏無狀態的
含義是指客戶端web瀏覽器和web服務器之間不需要建立持久的連接,這意味着當一個客戶端向
服務器發出請求(HttpRequest),然後web服務器返回響應(HttpResponse)之後連接就關閉了,
在web服務器上不保留連接的信息。
HTTP協議遵循請求(Request)/應答(Response)模型,瀏覽器向服務器發送請求,服務器處理
請求並返回適當的應答。其一次連接被構造成一次請求和應答。
HTTP通信過程
在完整的一次請求、應答模式中HTTP通信的過程爲以下七個步驟:
1、建立TCP連接
在HTTP協議開始工作之前,瀏覽器和服務器首先需要建立連接,該連接是通過TCP來完成的
2、瀏覽器向服務器發送請求指令
TCP連接建立了以後,瀏覽器就可以向服務器發送請求指令了。
常見的位POST和GET
3、瀏覽器發送請求頭消息
瀏覽器發送請求命令之後,還要以頭消息的形式向服務器發送一些別的信息,之後瀏覽器發送
一行空白行來通知服務器其已經結束了頭信息的發送。
4、Web服務器響應
瀏覽器發送請求後進行一些相關邏輯的處理之後,服務器會向客戶端瀏覽器返回應答。
例如:HTTP/1.1 200 OK 版本號+狀態碼
5、web服務器發送應答頭信息
如同客戶端一樣,服務器應答也會想用戶發送關於他自己的數據和被請求的文檔信息。
6、web服務器向瀏覽器發送數據
向瀏覽器發送頭信息,同樣以空白行來表示頭信息的發送結束。之後以Content-type應答
頭信息所描述的格式發送實際的數據。
7、web服務器關閉TCP連接
當實際的數據發送完畢之後,Web服務器關閉TCP連接。不過服務器或者瀏覽器頭信息
加入了Connection:keep-alive。TCP連接在數據發送完畢之後仍然保持的是打開狀態。
縮短了下一次連接建立的時間,節約了網絡帶寬。
HTTP請求格式
HTTP請求信息由三部分組成:
請求方法URI協議/版本、請求頭(Request Header)、正文
請求方法、URI、協議
HTTP/1.1 表示的是HTTP一些的版本,GET表示請求的方法,/sample.jsp表示資源URI。
在Intenet應用中常用的請求方法是GET和POST,當然還有其他的一些方法例如HEAD、PUT
URI完整的指定了要訪問的網絡資源,一般情況下只需要給出相對於服務器根目錄的相對目錄
即可。
上述中GET方法和POST方法由很大的區別,筆者會找個時間做一個總結。
請求頭信息
以一行空信息爲結束標誌,請求頭信息包含了一些客戶端環境信息和一些正文信息。
請求正文
請求正文包含客戶端提交的查詢字符串的信息。一般情況下查詢字符串信息是通過表單
傳遞給服務器,進行一些邏輯的處理,例如登錄,註冊等功能。
Servlet處理HTTP請求
瞭解了HTTP協議和HTTP請求的相關內容,我們可能會思考一個問題:Servlet中如何獲取
HTTP請求信息來實現相關的業務邏輯呢?
接下來筆者將實際進行一下演示,來說明Servlet對HTTP請求的處理。
閱讀源碼可以知道HTTP請求是封裝在HttpServletRequest對象中的。
不過這裏我們會發現HttpServletRequest是一個接口,是不能直接實例化的,不過根據Java
的多態性質我們不難猜想到,具體實例化的肯定是實現此接口的子類,不過我們如何知道是哪
個類呢?(其實這裏實例化的是Tomcat容器裏面的類)
利用反射嘛,合理的運用反射在一些框架的學習中是十分有必要的。
class org.apache.catalina.connector.RequestFacade這裏是筆者通過反射得到的結果,具體的類在Tomcat容器中,對於Tomcat的學習筆者
有時間的時候會進行下去的。
我們現在知道HttpServletRequest封裝了HTTP請求的相關信息,這些信息我們如何獲取呢?
讀者可以去查閱其源碼。這裏筆者給出一些比較常用的方法。
請求信息的獲取
getHeader(name):返回指定的請求頭的信息。
............
請求方法、URI信息的獲取
getMethod():獲取HTTP請求的方法。
getContextPath();獲取請求URI資源的上下文路徑
getServletPath();獲取Servlet的映射路徑
請求正文信息的獲取
getPrarameter(parameterName)
............................................................
請求派發
這裏Tomcat在實現了對HTTP請求的封裝之後,還提供了請求派發的功能:每個客戶的請求
可以傳遞給多個Servlet、web應用程序中的其他資源。整個的過程是在服務器端完成的,沒有
任何客戶端的參與不需要在客戶端瀏覽器和服務器之間傳遞什麼特殊的信息。
研究其源碼可以發現其是藉助於RequestDispatcher對象來實現的。
需要注意的是RequestDispatcher提供了兩種派發的方式:
include、forward();兩者的區別在於forward()方法只會輸出後面頁面的內容,而include()
方法兩個頁面都會輸出。
實例源碼演示
package com.kiritor.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class HelloServlet */ public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public HelloServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(request.getMethod()); System.out.println(request.getContextPath()); System.out.println(request.getHeader("User-Agent")); System.out.println(request.getParameter("username")); } }這裏我們直接看輸出結果吧:
至於其他的方法,筆者這裏就不多講了,讀者自己去看源碼,寫實例嘗試吧。
之後一篇文章將會就HTTP響應,以及Servlet如何處理HTTP的響應做一些總結、學習。
OK,這篇文章就到這兒了!