web筆記六:轉發(forward)和重定向(sendRedirect)

本章節將介紹轉發和重定向的區別,在瞭解它們之前,我們需要知道一句話:轉發是由服務器內部實現的,而重定向的工作則是由瀏覽器去執行,它們之間的區別也都是圍繞這這句話進行,它們之間的區別主要有三點。

一、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服務器目錄

說完不同點,下面結合共同點來講一下相對路徑、絕對路徑在轉發和重定向的具體變現是怎樣的。

  1. 首先我們先建立兩個類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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章