【Servlet與JSP】請求轉發與重定向

假設一個登陸系統,要求用戶輸入用戶名和密碼:

用戶在上面表單當中輸入了信息以後,點擊登陸按鈕(type="submit")將表單做爲請求參數進行提交。html

這一提交就有兩種形式:getpost
GET:顯式獲取,請求參數明晃晃地放入url(以?開始)中,經過TCP連接傳給目標服務頁。
POST:分郵獲取,先向目標服務器發出請求首部,如得到確定答覆(816 I'm a teapot! 100 Continue)以後向目標服務頁發出請求體,請求體被暗含。前端

通常出於必定安全性和功能性考慮(URL的長度有限直接致使GET自身的侷限性),像這種登陸請求通常都經過POST發送,並且POST能夠進行請求信息的編碼,而GET只有一種編碼方式(也是由於URL的編碼方式有限),但若是隻是用於用戶查詢的這種臨時性的信息出於速度考慮會使用GET(由於GET是直接發出一次請求)。安全

固然,這不是今天討論的重點服務器

咱們使用POST(僅討論這種方式)方式發出請求信息,服務端頁面內部嵌入的JSP代碼或服務端後臺的Servlet代碼(實際上,JSP嚴格說屬於後臺代碼,由於JSP能夠等價爲一個Servlet,只不過一般處理前端業務)就開始處理請求,服務端處理請求以後就要進行驗證處理,若是驗證經過就會以這個用戶信息登陸。less

因而咱們有了這樣的局面:
jsp

若是登陸正確,則服務端將主頁(index.jsp)呈現到用戶(客戶端)面前,不然將錯誤登陸的頁面(error.jsp)提示給用戶。post

然而,請求的處理方式就有了兩種:請求轉發(Request Dispatch)重定向(Redirection)編碼

  1. 請求轉發:服務端LoginServlet收到來自於login.jsp的請求,LoginServlet對請求的信息進行驗證,根據驗證結果,經過請求分發器(Request Dispatcher)將登陸的請求信息分發到index.jsperror.jsp(下文簡稱結果頁
  2. 重定向:服務端LoginServlet收到來自於login.jsp的請求,LoginServlet對請求的信息進行驗證,根據驗證結果,服務端向客戶端發出重定向到對應頁面的響應(301 Redirect),客戶端收到重定向響應以後進行第二次請求發送。

顯然,這兩個過程的事情是不同的,其結果也不同。url

請求轉發

小明:李華,麻煩告訴物理老師一聲,下節物理課改爲體育了
李華:可是,我是英語課表明,你應該去找牛頓同窗,他知道物理老師的辦公室,這樣吧我幫你轉告給他(默記:下節物理課改爲體育了)。
李華找到了牛頓同窗
李華:牛頓,告訴物理老師一聲,(回想到默記內容:下節物理課改爲體育了),下節物理課改爲體育了
牛頓:(默記:下節物理課改爲體育了)好的,我把這個消息轉告物理老師spa

請求轉發正是這樣的一個相似於傳火的過程:

login.jsp將用戶的登陸信息封成一個請求發送給LoginServletLoginServlet檢查無誤以後就把這個請求隨手轉發給了index.jsp,這樣一來index.jsp可以知道:

啊,原來是那個該死的管理員登陸了呢,我真巴不得踢他的屁股呢。

也就是說,請求的信息在轉發過程當中是被保留下來的,這當然是很好的。
請求轉發經過Servlet的request內置對象(主要負責請求的處理)的getDispatcher(url).forward(requ,resp)方法實現。表示向url頁面轉發請求。requresp參數一般直接填寫requestresponse這兩個內置對象,表示對當前的請求和響應進行傳遞。

因爲請求轉發是在服務端完成的,服務端將結果頁做爲一個response總體返回,所以客戶端根本察覺不到任何事情,地址欄指示爲處理該請求的Servlet的URI。
這也無形中埋下了一個隱患,因爲請求是一脈相承的,所以一旦用戶在這個過程當中一個不當心按了一下F5(刷新),整個轉發過程要從新走一遍,假設這個請求處理購買業務,那將是很是致命的(好比重複購買和重複支付)。

重定向

小明:李華,麻煩告訴物理老師一聲,下節物理課改爲體育了
李華:(心不在焉)我是英語課表明,你找錯人了,本身跟物理課表明牛頓同窗說去。
吃了個閉門羹,小明一臉尷尬的找到了牛頓同窗
小明:牛頓同窗……
牛頓:嗯??怎麼了??
小明:……(唉??我要說啥來着O.O……)

重定向是一種服務端的響應(Response),HTTP中規定的重定向的響應信息是3系的(301 Permanent moved302 Found)。
重定向,顧名思義,就是新確你的請求方,好比說,原本你在地址欄裏敲的AAA.com(純屬虛構,若有雷同不勝榮幸),可是AAA.com因業務調整遷移到了BBB.com,這種狀況下服務商一般會保留AAA.com的域名而後在此域名下提供一個重定向將你帶到BBB.com。

重定向的響應服務端發出,但重定向以後的請求仍然由客戶端發出。
重定向方式是經過內置對象responsesendRedirect(url)方法實現,由於根據HTTP的規定,一個規範的重定向響應必須包含一個重定向的目標地址[RFC 2616]。

The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).

HTTP/1.1 301 Moved Permanently
Location: http://www.example.org/index.asp

url就是規範中規定的目標地址。

可是,這個url自己也就表明了客戶端的第二次訪問請求,但一般重定向信息中僅僅包含目標頁面的URL,將此URL做爲新的訪問請求時,本來的登陸信息就不復存在了(由於新的訪問請求不包含這些內容)。
這樣一來,即便登陸成功,index.jsp也無從知曉是誰登陸了,他只能知道的是:

好像有個很厲害的傢伙登陸了耶,是誰呢,算了老實裝死就行了。

綜上,重定向的方式會致使請求丟失(Request Loss)

但這個問題應該有辦法解決吧

確實如此,回顧一下上面的GET請求方式,

GET:顯式獲取,請求參數明晃晃地放入url(以?開始)中,經過TCP連接傳給目標服務頁。

這也就意味着,我能夠把從POST獲取的請求再從新以GET的方式塞入URL中,這樣反饋給客戶端從新發送的請求就再一次包含了以前的信息。

可是!

正如前面所說的,因爲GET和POST之間的差別,這種作法可能會帶來某種風險。

那麼我看X度啦,X寶啦,都不會出現上面兩種狀況呢

其實,做爲登陸功能,通常仍是青睞採用重定向的方式(其實教務處的CAS認證跳轉也是重定向的方式),畢竟登陸了一溜十三招,發現地址欄仍是那個位置彷佛也是很是的古怪。
可是正如前面所說的,重定向有信息丟失的風險,由於重定向的內容每每不包含登陸信息。

因而乎另外一個內置對象就有了做用——會話(Sessions)

會話是服務端在服務器上建立的一個對象,專門用於對一個具體用戶進行交互,能夠簡單理解爲一個一對一服務員。 既然重定向會致使信息丟失,那麼就在重定向以前在服務端建立一個會話,在會話中指明登陸的信息,這樣重定向以後,會話內容在服務端天然是不會丟失的,而用戶從新訪問頁面的時候直接從會話讀取登陸信息就能夠了。

相關文章
相關標籤/搜索