重定向

servlet的兩種重定向方法的區別及應用

 

 

一 問題:  在servlet/JSP編程學習中,發現有兩種方法可以實現服務端輸出重定向,一種是通過forward方法(例如JSP中 的<jsp:forward page=”OtherPage.jsp”/>),另一種則是通過運用 javax.servlet.http.HttpServletResponse接口的sendRedirect方法(例如 response.sendRedirect(“OtherPage.jsp”);這兩種方法有什麼區別和聯繫呢?讓我們看下面的分析。

二 分析:(1)<JSP:FORWORD>

該 方法是利用服務器端先將數據輸出到緩衝區的機制,在把緩衝區(buffer)的內容發送到客戶端之前,原來的不發送,改爲發送該頁面的內容,如果 在<JSP:FORWORD>之前有很多輸出,前面的輸出已使緩衝區滿,將自動輸出到客戶端,那麼該語句將不起作用,這一點應該特別注意.
補充知識:輸出緩衝區
缺省情況下:服務端要輸出到客戶端的內容,不直接寫到客戶端,而是先寫到一個輸出緩衝區中.只有在下面三中情況下,纔會把該緩衝區的內容輸出到客戶端上:
1該JSP網頁已完成信息的輸出
2輸出緩衝區已滿
3JSP中調用了out.flush()或response.flushbuffer()
輸出緩衝區的大小可以用:<%@page buffer="none"|"nkb"%>或response.setBufferSize()設置,如下:
1設置輸出緩衝區的大小爲1KB。<%@page buffer="1kb"%>或response.setBufferSize(1);
2設置輸出緩衝區的大小爲0,即不緩衝。<%@page buffer="none" %>或response.setBufferSize(0);
用response.getBufferSize()或out.getBufferSize()可取的輸出緩衝區的大小,單位爲字節.
用response.isCommitted()可檢查看服務端是否已將數據輸出到客戶端. 如果返回值是TRUE則已將數據輸出到客戶端,是FALSE則還沒有。
(2)response.sendRedirect(“OtherPage.jsp”)
該 方法通過修改HTTP協議的HEADER部分,對瀏覽器下達重定向指令的,讓瀏覽器對在location中指定的URL提出請求,使瀏覽器顯示重定向網頁 的內容。該方法可以接受絕對的或相對的URLs。如果傳遞到該方法的參數是一個相對的URL,那麼Web container在將它發送到客戶端前會把它 轉換成一個絕對的URL。如果地址是相對的,沒有一個’/’,那麼Web container就認爲它是相對於當前的請求URI的。
因爲這個方法是通過修改HTTP協議的HEADER實現的重定義功能,而下面的方法也能改變HTTP HEADER屬性,他們的原理是一樣的.
<%
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
String newLocn="/index.html";
response.setHeader("Location",newLocn);
%>
補充知識:HTTP應答頭
 Web服務器響應瀏覽器或其他客戶程序的請求時,其應答一般由以下幾個部分組成:一個狀態行,幾個應答頭,一個空行,內容文檔。下面是一個最簡單的應答:
HTTP/1.1 200 OK
Content-Type: text/plain

Hello World
 
1設置狀態信息
狀 態行包含HTTP版本、狀態代碼、與狀態代碼對應的簡短說明信息。在大多數情況下,除了Content-Type之外的所有應答頭都是可選的。 Servlet可以利用狀態代碼來實現許多功能。例如,可以把用戶重定向到另一個網站,就像我們上邊所看到的那個例子。下面我們就通過這個機會具體討論各 種狀態代碼的含義以及利用這些代碼可以做些什麼。
如前所述,HTTP應答狀態行包含HTTP版本、狀態代碼和對應的狀態信息。由於狀態信息直接和狀態代碼相關,而HTTP版本又由服務器確定,因此需要Servlet設置的只有一個狀態代碼。

先給出常見的HTTP 1.1狀態代碼以及它們對應的狀態信息和含義,具體的使用方法我們接下來再做詳細的介紹。
100 Continue 初始的請求已經接受,客戶應當繼續發送請求的其餘部分。(HTTP 1.1新)
101 Switching Protocols 服務器將遵從客戶的請求轉換到另外一種協議(HTTP 1.1新)
200 OK 一切正常,對GET和POST請求的應答文檔跟在後面。如果不用setStatus 設置狀態代碼,Servlet默認使用202狀態代碼。
201 Created 服務器已經創建了文檔,Location頭給出了它的URL。
202 Accepted 已經接受請求,但處理尚未完成。
203 Non-Authoritative Information 文檔已經正常地返回,但一些應答頭可能不正確,因爲使用的是文檔的拷貝(HTTP 1.1新)。
204 No Content 沒有新文檔,瀏覽器應該繼續顯示原來的文檔。如果用戶定期地刷新頁面,而Servlet可以確定用戶文檔足夠新,這個狀態代碼是很有用的。
205 Reset Content 沒有新的內容,但瀏覽器應該重置它所顯示的內容。用來強制瀏覽器清除表單輸入內容(HTTP 1.1新)。
206 Partial Content 客戶發送了一個帶有Range頭的GET請求,服務器完成了它(HTTP 1.1新)。
300 Multiple Choices 客戶請求的文檔可以在多個位置找到,這些位置已經在返回的文檔內列出。如果服務器要提出優先選擇,則應該在Location應答頭指明。
301 Moved Permanently 客戶請求的文檔在其他地方,新的URL在Location頭中給出,瀏覽器應該自動地訪問新的URL。
302 Found 類似於301,但新的URL應該被視爲臨時性的替代,而不是永久性的。注意,在HTTP1.0中對應的狀態信息是“Moved Temporatily”,而HttpServletResponse中相應的常量是SC_MOVED_TEMPORARILY,而不是 SC_FOUND。
出現該狀態代碼時,瀏覽器能夠自動訪問新的URL,因此它是一個很有用的狀態代碼。爲此,Servlet提供了一個專用的方 法,即sendRedirect。使用response.sendRedirect(url)比使用 response.setStatus(response.SC_MOVED_TEMPORARILY)和 response.setHeader("Location",url)更好。這是因爲:

首先,代碼更加簡潔。
第二,使用sendRedirect,Servlet會自動構造一個包含新鏈接的頁面(用於那些不能自動重定向的老式瀏覽器)。
最後,sendRedirect能夠處理相對URL,自動把它們轉換成絕對URL。
注意這個狀態代碼有時候可以和301替換使用。例如,如果瀏覽器錯誤地請求http://host/~user(缺少了後面的斜槓),有的服務器返回301,有的則返回302。

嚴格地說,我們只能假定只有當原來的請求是GET時瀏覽器纔會自動重定向。請參見307。

303 See Other 類似於301/302,不同之處在於,如果原來的請求是POST,Location頭指定的重定向目標文檔應該通過GET提取(HTTP 1.1新)。
304 Not Modified 客戶端有緩衝的文檔併發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務器告訴客戶,原來緩衝的文檔還可以繼續使用。
305 Use Proxy 客戶請求的文檔應該通過Location頭所指明的代理服務器提取(HTTP 1.1新)。

307 Temporary Redirect 和302(Found)相同。許多瀏覽器會錯誤地響應302應答進行重定向,即使原來的請求是POST,即使它實際上只能在POST請求的應答是303時 才能重定向。由於這個原因,HTTP 1.1新增了307,以便更加清除地區分幾個狀態代碼:當出現303應答時,瀏覽器可以跟隨重定向的GET和POST請求;如果是307應答,則瀏覽器只 能跟隨對GET請求的重定向。
注意,HttpServletResponse中沒有爲該狀態代碼提供相應的常量。(HTTP 1.1新)

400 Bad Request 請求出現語法錯誤。
401 Unauthorized 客戶試圖未經授權訪問受密碼保護的頁面。應答中會包含一個WWW-Authenticate頭,瀏覽器據此顯示用戶名字/密碼對話框,然後在填寫合適的Authorization頭後再次發出請求。
403 Forbidden 資源不可用。服務器理解客戶的請求,但拒絕處理它。通常由於服務器上文件或目錄的權限設置導致。
404 Not Found 無法找到指定位置的資源。這也是一個常用的應答,HttpServletResponse專門提供了相應的方法:sendError(message)。
405 Method Not Allowed 請求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)對指定的資源不適用。(HTTP 1.1新)
406 Not Acceptable 指定的資源已經找到,但它的MIME類型和客戶在Accpet頭中所指定的不兼容(HTTP 1.1新)。
407 Proxy Authentication Required 類似於401,表示客戶必須先經過代理服務器的授權。(HTTP 1.1新)
408 Request Timeout 在服務器許可的等待時間內,客戶一直沒有發出任何請求。客戶可以在以後重複同一請求。(HTTP 1.1新)
409 Conflict 通常和PUT請求有關。由於請求和資源的當前狀態相沖突,因此請求不能成功。(HTTP 1.1新)
410 Gone 所請求的文檔已經不再可用,而且服務器不知道應該重定向到哪一個地址。它和404的不同在於,返回407表示文檔永久地離開了指定的位置,而404表示由於未知的原因文檔不可用。(HTTP 1.1新)
411 Length Required 服務器不能處理請求,除非客戶發送一個Content-Length頭。(HTTP 1.1新)
412 Precondition Failed 請求頭中指定的一些前提條件失敗(HTTP 1.1新)。
413 Request Entity Too Large 目標文檔的大小超過服務器當前願意處理的大小。如果服務器認爲自己能夠稍後再處理該請求,則應該提供一個Retry-After頭(HTTP 1.1新)。
414 Request URI Too Long URI太長(HTTP 1.1新)。
416 Requested Range Not Satisfiable 服務器不能滿足客戶在請求中指定的Range頭。(HTTP 1.1新)
500 Internal Server Error 服務器遇到了意料不到的情況,不能完成客戶的請求。
501 Not Implemented 服務器不支持實現請求所需要的功能。例如,客戶發出了一個服務器不支持的PUT請求。
502 Bad Gateway 服務器作爲網關或者代理時,爲了完成請求訪問下一個服務器,但該服務器返回了非法的應答。
503 Service Unavailable 服務器由於維護或者負載過重未能應答。例如,Servlet可能在數據庫連接池已滿的情況下返回503。服務器返回503時可以提供一個Retry-After頭。
504 Gateway Timeout 由作爲代理或網關的服務器使用,表示不能及時地從遠程服務器獲得應答。(HTTP 1.1新)
505 HTTP Version Not Supported 服務器不支持請求中所指明的HTTP版本。(HTTP 1.1新)
如前所述,HTTP應答狀態行包含HTTP版本、狀態代碼和對應的狀態信息。由於狀態信息直接和狀態代碼相關,而HTTP版本又由服務器確定,因此需要Servlet設置的只有一個狀態代碼。拿我們上邊的例子來看。其中有一句就是設置HTTP應答頭的狀態代碼的,是:
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
Servlet 設置狀態代碼一般使用HttpServletResponse的setStatus方法。setStatus方法的參數是一個整數(即狀態代碼),不過爲 了使得代碼具有更好的可讀性,可以用HttpServletResponse中定義的常量來避免直接使用整數。這些常量根據HTTP 1.1中的標準狀態信息命名,所有的名字都加上了SC前綴(Status Code的縮寫)並大寫,同時把空格轉換成了下劃線。也就是說,與狀態代碼301對應的狀態信息是“Moved Permanently”,則HttpServletResponse中的對應常量名字爲SC_MOVED_PERMANENTLY。但有兩個例外:和狀 態代碼302對應的常量根據HTTP 1.0命名爲SC_MOVED_TEMPORARILY,而不是SC_FOUND,而307沒有對應的常量。   
    雖然設置狀態代碼一般使用的是response.setStauts(int)方法,但爲了簡單起見,HttpServletResponse爲兩種常見 的情形提供了專用方法:sendError方法生成一個404應答,同時生成一個簡短的HTML錯誤信息文檔;sendRedirect方法生成一個 302應答,同時在Location頭中指示新文檔的URL。這種方法就是我們前邊提到的 response.sendRedirect(“OtherPage.jsp”)實現重定向的方法的原理。它與301應答,既 response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY)的區別請看上邊狀態列表的 紅色標記部分,這裏不再重複。
  
2設置HTTP應答頭
設置HTTP應答頭往往和設置狀態行 中的狀態代碼結合起來。例如,有好幾個表示“文檔位置已經改變”的狀態代碼都伴隨着一個Location頭,而401(Unauthorized)狀態代 碼則必須伴隨一個WWW-Authenticate頭。這些都在相應的狀態代碼的狀態信息說明中都提到了。
     然而,即使在沒有設置特殊含義的狀態代碼時,指定應答頭也是很有用的。應答頭可以用來完成:設置Cookie,指定修改日期,指示瀏覽器按照指定的間隔刷 新頁面,聲明文檔的長度以便利用持久HTTP連接,……等等許多其他任務。還拿我們上邊的例子來看,其中有一句就是設置HTTP應答頭的,是:
  response.setHeader("Location",newLocn);
設置應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個參數,分別表示應答頭的名字和值。和設置狀態代碼相似,設置應答頭應該在發送任何文檔內容之前進行。
應答頭 說明
Allow 服務器支持哪些請求方法(如GET、POST等)。
Content-Encoding 文檔的編碼(Encode)方法。只有在解碼之後纔可以得到Content-Type頭指定的內容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔 的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應該通過查看Accept-Encoding頭(即request.getHeader("Accept- Encoding"))檢查瀏覽器是否支持gzip,爲支持gzip的瀏覽器返回經gzip壓縮的HTML頁面,爲其他瀏覽器返回普通頁面。
Content-Length 表示內容長度。只有當瀏覽器使用持久HTTP連接時才需要這個數據。如果你想要利用持久連接的優勢,可以把輸出文檔寫入 ByteArrayOutputStram,完成後查看其大小,然後把該值放入Content-Length頭,最後通過 byteArrayStream.writeTo(response.getOutputStream()發送內容。
Content-Type 表示後面的文檔屬於什麼MIME類型。Servlet默認爲text/plain,但通常需要顯式地指定爲text/html。由於經常要設置 Content-Type,因此HttpServletResponse提供了一個專用的方法setContentTyep。
Date 當前的GMT時間。你可以用setDateHeader來設置這個頭以避免轉換時間格式的麻煩。
Expires 應該在什麼時候認爲文檔已經過期,從而不再緩存它?
Last-Modified 文檔的最後改動時間。客戶可以通過If-Modified-Since請求頭提供一個日期,該請求將被視爲一個條件GET,只有改動時間遲於指定時間的文 檔纔會返回,否則返回一個304(Not Modified)狀態。Last-Modified也可用setDateHeader方法來設置。
Location 表示客戶應當到哪裏去提取文檔。Location通常不是直接設置的,而是通過HttpServletResponse的sendRedirect方法,該方法同時設置狀態代碼爲302。
Refresh 表示瀏覽器應該在多少時間之後刷新文檔,以秒計。除了刷新當前文檔之外,你還可以通過setHeader("Refresh", "5; URL=http://host/path")讓瀏覽器讀取指定的頁面。
注 意這種功能通常是通過設置HTML頁面HEAD區的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">實現,這是因爲,自動刷新或重定向對於那些不能使用CGI或Servlet的 HTML編寫者十分重要。但是,對於Servlet來說,直接設置Refresh頭更加方便。

注意Refresh的意義是“N秒之後刷新本頁面或訪問指定頁面”,而不是“每隔N秒刷新本頁面或訪 問指定頁面”。因此,連續刷新要求每次都發送一個Refresh頭,而發送204狀態代碼則可以阻止瀏覽器繼續刷新,不管是使用Refresh頭還是 <META HTTP-EQUIV="Refresh" ...>。

注意Refresh頭不屬於HTTP 1.1正式規範的一部分,而是一個擴展,但Netscape和IE都支持它。

Server 服務器名字。Servlet一般不設置這個值,而是由Web服務器自己設置。
Set-Cookie 設置和頁面關聯的Cookie。Servlet不應使用response.setHeader("Set-Cookie", ...),而是應使用HttpServletResponse提供的專用方法addCookie。參見下文有關Cookie設置的討論。
WWW-Authenticate 客戶應該在Authorization頭中提供什麼類型的授權信息?在包含401(Unauthorized)狀態行的應答中這個頭是必需的。例 如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。
注意Servlet一般不進行這方面的處理,而是讓Web服務器的專門機制來控制受密碼保護頁面的訪問(例如.htaccess)。

    到此我們應該可以理解用下面代碼實現重定向的原理:修改HTTP協議的HEADER部分,對瀏覽器下達重定向指令的,讓瀏覽器對在location中指定的URL提出請求,使瀏覽器顯示重定向網頁的內容。
<%
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 設置HTTP應答頭狀態代碼
String newLocn="/index.html";
response.setHeader("Location",newLocn); 設置HTTP應答頭
%>

三 總結:
通過上邊的分析,我們清楚了這兩種服務器端重 定向方法的原理,<jsp:forward>是利用服務器端先將數據輸出到緩衝區的機制,在把緩衝區的內容發送到客戶端之前,通過停止調用頁 的處理,將執行轉向響應的頁面,從而實現的重定位功能,原調用頁的輸出緩衝區中任何尚未在瀏覽器中顯示(刷新)的內容將被清楚,不再顯示。
     而response.sendRedirect(“OtherPage.jsp”)是通過修改HTTP協議的HEADER部分,對瀏覽器下達重定向指令的,讓瀏覽器對在location中指定的URL提出請求,使瀏覽器顯示重定向網頁的內容的。

四 對比:
1 forward方法是在Web container內部工作的。SendRedirect方法需要到客戶端的一個往返。所以forward方法要比sendreRirect要快
2 forward方法只能重定向到同一個Web應用程序中的一個資源。而sendRedirect方法可以重定向到任何URL
3 forward方法還將原始的HTTP請求對象(request)轉到目錄頁。而sendRedirect方法的功能是觸發瀏覽器轉向指定的URL,並不會將原始請求對象轉發。

在例:C:\Tomcat 5.0\webapps\test\regiester10中我們可以看到在WELCOME。JSP中有:
<tr><td>姓名:<%=request.getParameter("userName")%></td></tr>
當在LOGIN.JSP中用response.sendRedirect("welcome.jsp");重定向到WELCOME.JSP時,輸出爲:
                                                                        姓名:null
當在LOGIN.JSP中用<jsp:forward page = "welcome.jsp"/>重定向到WELCOME.JSP時,輸出爲:
                                                                        姓名:wangjian
4.sendRedirect能夠處理相對URL,自動把它們轉換成絕對URL。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章