本章節將介紹轉發和重定向的區別,在瞭解它們之前,我們需要知道一句話:轉發是由服務器內部實現的,而重定向的工作則是由瀏覽器去執行,它們之間的區別也都是圍繞這這句話進行,它們之間的區別主要有三點。
一、URL地址是否變化
由於轉發是在服務器內部執行的,瀏覽器並不知道請求的內容轉發到其他地方進行處理,所以瀏覽器上面的地址欄是不變的。而重定向是由瀏覽器執行的,所以URL會發生變化。
結論:
轉發:URL不變
重定向:URL變化
二、請求信息是否保留
請求信息包括parameter、attribute等,由於轉發是在服務器內部執行的,所以這些請求信息都會保留傳遞到目的servlet的HttpServletRequest中,而重定向則相當於重新發起一個新的請求,不會保留請求信息。
結論:
轉發:保留請求信息
重定向:不保留請求信息
三、根目錄(/)
轉發是在內部的,所以根目錄對應的就是web應用的目錄,而瀏覽器是針對web服務器發起的請求,所以重定向的根目錄爲web服務器目錄。例如我們將helloweb.war包放到tomcal/webapps目錄下,啓動tomcat。那麼http://localhost:8080/helloweb/
就是我們web應用的根目錄,http://localhost:8080/
就是我們web服務器的根目錄。
總結:
轉發:web應用目錄
重定向:web服務器目錄
說完不同點,下面結合共同點來講一下相對路徑、絕對路徑在轉發和重定向的具體變現是怎樣的。
- 首先我們先建立兩個類MyServlet、MyServlet_02,分別設置url-mapping爲 /a/*、/b/*
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/a/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet2</servlet-name>
<url-pattern>/b/*</url-pattern>
</servlet-mapping>
2.在兩個servlet的service方法分別插入以下代碼
System.out.println("===MyServlet===");
try {
System.out.println(request.getRequestURL());
Thread.sleep(1000);//防止轉發/重定向到當前servlet一下子打印過多信息。
String url="";//
//request.getRequestDispatcher(url).forward(request, response);//轉發
//response.sendRedirect(url);//重定向
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("===MyServlet_02===");
System.out.println(request.getRequestURL());
response.getWriter().print("hello world!");
一、帶斜槓(/)開頭的的相對路徑:
我們設置String url="/b/abc";
在瀏覽器輸入http://localhost:8080/helloweb/a/abc
,結果如下如下:
轉發(forward):request.getRequestDispatcher(url).forward(request, response);
重定向(sendRedirect):response.sendRedirect(url);
我們可以肯定,上面說的區別一、三的觀點是正確的。
二、不帶斜槓(/)的相對路徑
我們設置String url="b/abc"
(注意這裏比前面的少了個斜槓),在瀏覽器輸入http://localhost:8080/helloweb/a/abc
,結果如下:
這裏重定向和轉發的控制檯打印都是一樣的,請求將死循環調用MyServlet,但是每次URL都不一樣,每個URL都比上一個多了一個b/
,如果把url設置爲b/abc/
,那麼每個URL都會比上一個多出b/abc/
,由此可以知道,此時請求的路徑是相對於請求URL最後一個斜槓。
三、絕對路徑
絕對路徑就比較好理解了,但是轉發(forward)不支持絕對路徑的寫法,它會把要重寫的URL當成是不帶斜槓的相對路徑來處理。
轉發和重定向的區別到這裏就講完了,讓我們回到第二張圖,我們一開始請求的是http://localhost:8080/helloweb/a/abc
,但是我們在MyServlet_02中拿到的URL卻是轉發後的URLhttp://localhost:8080/helloweb/b/abc
,那麼,我們怎麼拿到轉發前的URL呢?
String requestUrl=""+request.getAttribute("javax.servlet.forward.request_uri");
在轉發之前,web容器會將轉發前的URL信息保存到request的attribute中,我們在MyServlet_02的service方法中插入以下代碼查看都有什麼信息:
Enumeration<String> names = request.getAttributeNames();
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
System.out.println(key+":"+request.getAttribute(key));
}
輸出:
javax.servlet.forward.request_uri:/helloweb/a/abc
javax.servlet.forward.context_path:/helloweb
javax.servlet.forward.servlet_path:/a
javax.servlet.forward.path_info:/abc
javax.servlet.forward.mapping:org.apache.catalina.core.ApplicationMapping$MappingImpl@b7d9f69
注意:只針對轉發(forward),不是重定向
總結:
request.getRequestDispatcher(url).forward(request, response);//轉發
response.sendRedirect(url);//重定向
(╯‵□′)╯ | 轉發(forward) | 重定向(sendRedirect) |
---|---|---|
瀏覽器URL地址是否發送改變 | 不變 | 變 |
請求信息是否保留 | 保留 | 不保留 |
相對路徑(帶/) | 相對當前web應用 | 相對於web服務器 |
相對路徑(不帶/) | 相對當前請求URL最後一個斜槓(/) | 相對當前請求URL最後一個斜槓(/) |
絕對路徑 | 不支持,效果類似於相對路徑(不帶/) | 重定向到指定的URL |
最後,附上代碼:
MyServlet.class
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("===MyServlet===");
try {
System.out.println(request.getRequestURL());
Thread.sleep(1000);//防止轉發/重定向到當前servlet一下子打印過多信息。
String url="/b/abc";
request.getRequestDispatcher(url).forward(request, response);//轉發
//response.sendRedirect(url);//重定向
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}
MyServlet_02.class
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet_02 extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("===MyServlet_02===");
String requestUrl=""+request.getAttribute("javax.servlet.forward.request_uri");
Enumeration<String> names = request.getAttributeNames();
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
System.out.println(key+":"+request.getAttribute(key));
}
System.out.println(request.getRequestURL());
response.getWriter().print("hello world!");
}
@Override
public void destroy() {
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.hxl.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>MyServlet2</servlet-name>
<servlet-class>com.hxl.MyServlet_02</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/a/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet2</servlet-name>
<url-pattern>/b/*</url-pattern>
</servlet-mapping>
</web-app>