forward, redirect的區別

來源:互聯網
上載者:User

這次使用者可以在首頁選擇自己喜歡的顏色,進入對應的頁面。

選擇綠色,會進入綠色介面:

選擇紅色,會進入紅色介面:

好的,這裡我們會看到四個頁面:

  1. index.jsp中選擇顏色,點擊按鈕後提交到test.jsp。

  2. test.jsp取得使用者選擇的顏色,根據顏色值顯示對應的頁面。

  3. 如果選擇了紅色,就顯示red.jsp。

  4. 如果選擇了綠色,就顯示green.jsp。

在這裡例子裡,index.jsp,red.jsp,green.jsp中的內容都是一樣的,所有的玄機都在test.jsp中。

現在面臨的問題是如何在test.jsp決定實現red.jsp或者green.jsp,我們可以在forward和redirect中任選其一。

3.2. 如果用forward

test.jsp中需要這樣寫:

<%@ page contentType="text/html; charset=gb2312"%><%    String color = request.getParameter("color");    if ("red".equals(color)) {        request.getRequestDispatcher("red.jsp").forward(request, response);    } else if ("green".equals(color)) {        request.getRequestDispatcher("green.jsp").forward(request, response);    }%>        

略過取得參數與比較參數值不提,只關注forward的部分:

request.getRequestDispatcher("red.jsp").forward(request, response);        

首先調用request的getRequestDispatcher()方法,獲得對應red.jsp的轉寄站,然後調用forward()方法執行請求轉寄。結果使用者看到的就是red.jsp中的結果了,一個紅色的頁面。

這裡請大家注意一下瀏覽器的url地址:

選擇紅色頁面時:

選擇綠色頁面時:

於是,無論轉寄至red.jsp還是green.jsp,地址欄上顯示的都是test.jsp。

這是為什麼呢?通過下面的流程圖會讓我們容易理解:

  1. 瀏覽器向test.jsp發送請求。

  2. test.jsp計算客戶選擇的顏色,將請求轉寄至red.jsp。

  3. red.jsp返迴響應給瀏覽器。

這下知道為什麼瀏覽器的地址沒有變化了吧?因為瀏覽器只是執行了對test.jsp的請求,test.jsp到red.jsp的部分是在伺服器內執行的,瀏覽器並不知道伺服器裡到底發生了什麼,它只知道自己獲得的響應是test.jsp發回來的,甚至不知道伺服器還有個red.jsp。

這就是請求轉寄forward了。例子見lingo-sample/03-01/。

3.3. 如果用redirect

test.jsp中需要這樣寫:

<%@ page contentType="text/html; charset=gb2312"%><%    String color = request.getParameter("color");    if ("red".equals(color)) {        response.sendRedirect("red.jsp");    } else if ("green".equals(color)) {        response.sendRedirect("green.jsp");    }%>        

略過取得參數與比較參數值不提,只關注redirect的部分:

response.sendRedirect("red.jsp");        

response翻譯過來就是響應,代表著http響應。調用response的sendRedirect("red.jsp")方法,將頁面重新導向到red.jsp。

再請大家注意一下瀏覽器的url地址:

選擇紅色頁面時:

選擇綠色頁面時:

與forward不同,url地址一直在變化,紅色的時候顯示red.jsp,綠色的時候顯示green.jsp。

再看一下流程圖吧:

  1. 瀏覽器向test.jsp發送請求。

  2. test.jsp計算客戶選擇的顏色,向瀏覽器發送一個頁面重新導向(redirect)的響應,響應中包含red.jsp的url地址。

  3. 瀏覽器根據頁面重新導向(redirect)響應中的red.jsp地址,再次向伺服器發送請求,這次請求的就是red.jsp了。

  4. red.jsp執行,返迴響應。

redirect會觸發另一個請求響應流程,第二次請求的時候是由瀏覽器發起對red.jsp的請求,所以url地址改變了。

這就是頁面重新導向redirect了。例子見lingo-sample/03-02/。

3.4. forward和redirect的問題3.4.1. 絕對路徑與相對路徑
  1. 如果咱們使用的URL網址是以“/”開頭的,那麼這個網址就叫做絕對路徑。

  2. 如果咱們使用的URL網址不是“/”開頭的,那麼這個網址就叫做相對路徑。

3.4.1.1. 相對路徑

在相對路徑上,兩者的表現是相同的。

看看lingo-sample/03-03/這個例子,如果我們去請求relative/forward.jsp或redirect.jsp,然後從這裡再跳轉向它下面的result/result.jsp會怎樣呢?

  1. forward的例子:

    <%request.getRequestDispatcher("result/result.jsp").forward(request, response);%>                        

    這裡的相對路徑就是result/result.jsp。

    因為剛剛請求的test.jsp是在/03-03/relative/下,所以我們的當前路徑就是/03-03/relative/,執行forward的時候會尋找當前路徑下的result/result.jsp,找到之後便轉寄請求。

  2. redirect的例子:

    <%response.sendRedirect("result/result.jsp");%>                        

    這裡的相對路徑也是result/result.jsp。

    因為剛剛請求的test.jsp是在/03-03/relative/下,所以我們的當前路徑就是/03-03/relative/,執行redirect的時候會把當前路徑加上result/result.jsp,把結果作為重新導向的地址發送給瀏覽器,瀏覽器再去請求/03-03/relative/result/result.jsp,從而得到響應。

3.4.1.2. 絕對路徑

問題出現了,絕對路徑在forward和redirect中出現了差別,還是剛才的情況,但使用絕對路徑的時候寫法便不同了。

  1. forward的例子:

    <%request.getRequestDispatcher("/relative/result/result.jsp").forward(request, response);%>                        

    這裡的絕對路徑就是/relative/result/result.jsp。

    在本地測試時,forward把http://localhost:8080/03-03/當作根路徑,在它的基礎上計算絕對路徑。

    這是由jsp的部署方式決定的,webapp裡可以放好多項目,為了讓這些項目可以互不影響、獨立運行,不能讓請求從一個項目直接在伺服器內部轉移到另一個項目。為了防止出現這種情況,在執行forward的時候乾脆把項目的路徑當作根目錄,開發人員看不到其他項目,也就不會出現問題了。

  2. redirect的例子:

    <%response.sendRedirect("/03-03/absolute/result/result.jsp");%>                        

    這裡的絕對路徑卻是/03-03/absolute/result/result.jsp。

    在本地測試時,redirect把http://localhost:8080/當作根路徑,在它的基礎上計算絕對路徑。

    因為rct會edire讓瀏覽器重新發起一個新請求,所以不會攪亂伺服器裡多重專案之間的關係,也就不需要對它做限制,如果需要在多重專案之間進行跳轉,就只能使用redirect。不過因為重新發起了新的請求,上次請求的那些資料都會丟失,如果有什麼重要的資料,記得要重新設定。

3.4.2. forward導致找不到圖片

找不到圖片,找不到js指令碼,找不到css樣式表,都屬於這個問題。

要示範這個問題,是非常容易的,只需要滿足兩個條件:

  1. forward前後的jsp頁面不在一個目錄下。

  2. forward後的jsp頁面裡使用相對路徑引用一些資源,圖片,js指令碼,css樣式表什麼的。

03-04裡就類比了這樣一個環境,你進入http://localhost:8080/03-04/,選擇“有問題的”:

開啟03-04可以看到如下的目錄結構:

|--+ 03-04   |--- index.jsp   |--- test.jsp   |--+ result      |--- success.jsp      |--- failure.jsp      |--- lingo.png            

剛才咱們看到的頁面是failure.jsp,它裡邊顯示圖片的部分是:

<img src="lingo.png" />            

這時候就有疑問了,lingo.png和failure.jsp明明在同一個目錄下,為什麼無法顯示。

現在請在無法顯示的圖片上,點擊滑鼠右鍵,選擇屬性,讓我們看一片的請求地址:

圖片的位置本來在http://localhost:8080/03-04/result/lingo.png,但請求的地址卻是http://localhost:8080/03-04/lingo.png。問題就是丟掉了中間的/result。

再試一次index.jsp上的“沒問題的”:

這次我們看到的頁面是success.jsp,它裡邊顯示圖片的部分是:

<img src="result/lingo.png" />            

結果手工加上result這段路徑後就可以顯示圖片了。

這個問題還要追溯到瀏覽器對html的處理方式,在html裡包含的圖片,css樣式表,js指令碼,視頻等等外部資源,都需要瀏覽器再次向伺服器發起請求。

如果這些外部資源使用了相對路徑,瀏覽器就會在當前請求路徑的基礎上,加上相對路徑拼接出完整的http請求,發送給伺服器。這個例子中,我們請求http://localhost:8080/03-04/test.jsp,瀏覽器得到的當前路徑就是http://localhost:8080/03-04/,failure.jsp中圖片的相對路徑是lingo.png,那麼拼接的結果是http://localhost:8080/03-04/lingo.png。

不要怪瀏覽器太傻,是因為使用forward的時候瀏覽器並不清楚這些改變。它一直認為,既然自己請求的是test.jsp,返回的自然就是test.jsp的內容,那麼再使用test.jsp當作當前路徑去計算相對路徑當然沒有問題。是我們欺騙了瀏覽器,在伺服器偷偷改變了請求流向,返回了其他頁面的內容。

清楚了以上的請求流程,就知道如何應對這種問題了。

  1. 第一種方法:不要在不同目錄之間使用forward做請求轉寄,保證當前路徑不發生變化。

  2. 第二種方法:像上例一樣修改圖片路徑,或全部改為絕對路徑。

請根據實際需要進行選擇。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.