1.引子
轉發和重定向是我們在做web項目中常用到的兩個術語,有必要理清兩者的區別和與之相關的參數、屬性獲取問題。
2.轉發和重定向
1).轉發
轉發是服務器行為,將當前請求(Request)和響應(Response)處理打包發送給目標服務(Servlet),這樣下一個目標服務就能獲取或操作上一個服務中的請求和響應。
客戶瀏覽器發送http請求—>web服務器接受此請求—>調用內部的一個方法在容器內部完成請求處理和轉發動作—>將目標資源 發送給客戶
轉發行為是同一次請求,其URL地址仍是以前的地址,不會發生變化,但頁面內容卻是新頁面的東西了。轉發只能是在同一應用中使用,不能跨應用轉發請求,比如,京東頁面的請求就不可能轉發給淘寶的服務器。
2).重定向
重定向就如其名字一樣,是將頁面定位到一個新位置。重定向客戶端行為,是全新的請求,客戶端不能保存當前的請求,在定位到新的頁面或servlet服務時,上次的請求超出請求的作用范圍了,那個請求即失效了。
客戶瀏覽器發送http請求—>web服務器接受后發送302狀態碼響應及對應新的location給客戶瀏覽器—>客戶瀏覽器發現 是302響應,則自動再發送一個新的http請求,請求url是新的location地址—>服務器根據此請求尋找資源並發送給客戶。
重定向至少是兩次請求,重定向后URL地址是新的地址了,當然頁面內容也更新為目標頁面的內容了。重定向可以定位到任意頁面,可以跨越不同的應用程序。比如,天貓的頁面就可以重定向到淘寶的頁面上。
參數(parameter)、屬性(attribute)的區別,可以看我另一篇帖子-----Servlet中的屬性(attribute)和參數(parameter)的區別
3.簡單示例
登錄頁html代碼
<form action="loginServlet" method="post"> 用戶名: <input type="text" name="username" /> <br/> 密 碼: <input type="password" name="pwd"/><br/> <!-- 默認的submit,提交給loginServlet處理 --> <input type="submit" value="提交至將轉發的servlet"> <br/> <!-- 一個表單內容可以提交給不同的servlet,而formaction屬性值就對應提交的目標地址, 這里提交給loginServlet2進行請求處理 --> <input type="submit" formaction="loginServlet2" value="提交至將重定向的servlet"> </form>
要轉發的servlet
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String name=request.getParameter("username"); String pwd=request.getParameter("pwd"); System.out.println("用戶名:"+name+"\t密碼:"+pwd); //request域中設置一個屬性 request.setAttribute("nowDate", new Date()); //轉發 request.getRequestDispatcher("forward_page.jsp?url_param=test_url_param").forward(request, response); }
要重定向的servlet
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String name=request.getParameter("username"); String pwd=request.getParameter("pwd"); System.out.println("用戶名:"+name+"\t密碼:"+pwd); //request域中設置一個屬性 request.setAttribute("nowDate", new Date()); //重定向 response.sendRedirect("redirect_page.jsp?url_param=test_url_param"); }
將轉發的登錄頁面
轉發頁的html代碼
<body> <h3>這是一個轉發后的頁面</h3> request中獲取參數(用戶名):<label>${param.username}</label> <br/> request中獲取參數(密碼):<label>${param.pwd}</label> <br/> request中獲取的屬性(‘nowDate’):<label>${nowDate}</label> <br/> url中獲取的一個參數:<label>${param.url_param}</label> <br/> </body>
servlet轉發到的頁面
從上圖可以看出,所有的參數和屬性(包括url中拼接的參數)都可以正確地獲取,並顯示在頁面上。但url地址還是"loginServlet",不是當前頁面所對應的"forward_page.jsp"地址。
將重定向的登錄頁面
重定向頁的HTML代碼
<body> <h3>這是一個重定向后的頁面</h3> request中獲取參數(用戶名):<label><c:out value="${param.username}" default="空"/></label> <br/> request中獲取參數(密碼):<label><c:out value="${param.pwd}" default="空"/></label> <br/> request中獲取屬性‘nowDate’:<label><c:out value="${nowDate}" default="空"/></label> <br/> url中獲取的一個參數:<label><c:out value="${param.url_param}" default="空"/></label> <br/> </body>
servlet重定向到的頁面
從上圖可以看出,上次請求的所有屬性、參數均不能獲取到。另外url地址更新了,不再是servlet的映射地址了,而當前新頁面的"redirect_page.jsp"地址。
除此之外,可以看到重定向的URL中拼接的鍵值對參數“url_param=test_url_param”在新頁面還是能獲取到的。
4.總結
1.重定向,是一次新的請求,不能獲得上次請求中的參數、屬性;轉發,是同一次請求,之前所有的參數、屬性在新的頁面或servlet中都可見的,它們保存在同一個request域中。
2.轉發操作,(即使轉至新頁面)其URL地址不會變化;而在重定向操作中,URL地址會更新變為重定向的目標地址。
3.若要頁面內容、URL地址均更新,並且新頁面還要獲取上次請求的參數、屬性,可以通過一種曲線救國的方式實現:在重定向的URL中以鍵值對的方式來拼接上次請求的參數、屬性;並在新頁面中通過EL表達式“${param.name}”獲取。