JavaWeb中轉發(fā)與重定向的區(qū)別小結
在一個web應用中通過兩種方式,可以完成資源的跳轉:
- 第一種方式:轉發(fā)
- 第二種方式:重定向
1. Forward 轉發(fā)
轉發(fā) :指內部轉發(fā)。當一個Servlet處理請求的時候,它可以決定自己不繼續(xù)處理,而是轉發(fā)給另一個Servlet處理。
// 獲取請求轉發(fā)器對象
RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
// 調用請求轉發(fā)器對象的forward方法完成轉發(fā)
dispatcher.forward(request, response);
// 合并一行代碼
request.getRequestDispatcher("/dept/list").forward(request, response);
// 轉發(fā)的時候是一次請求,不管你轉發(fā)了多少次。都是一次請求。
// AServlet轉發(fā)到BServlet,再轉發(fā)到CServlet,再轉發(fā)到DServlet,不管轉發(fā)了多少次,都在同一個request當中。
// 這是因為調用forward方法的時候,會將當前的request和response對象傳遞給下一個Servlet。注意: 因為轉發(fā)是服務器內部的進行的,所以 request.getRequestDispatcher(/不要項目名的).forward(request, response);編寫的轉發(fā)路徑是不要加項目名的。
舉例: 瀏覽器向 AServlet 發(fā)送請求,AServlet 將該請求 “轉發(fā)”給了 BServlet。但是前端的瀏覽器并不知道該請求被 BServlet 處理了,瀏覽器的地址欄上顯示的還是發(fā)送給 AServlet 請求的路徑信息。
package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AServlet extends HttpServlet {
// 地址欄上回車操作是 doGet()請求
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 轉發(fā)到 BServlet,轉發(fā)的路徑不要加項目名
request.getRequestDispatcher("/b").forward(request, response);
}
}package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設置瀏覽器端顯示響應的,格式類型,以及字符集
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("<h2> 這里是BServlet 的響應處理 </h2>");
}
}
轉發(fā)是由WEB服務器來控制的。A資源跳轉到B資源,這個跳轉動作是Tomcat服務器內部完成的 ,而我們前端也就是瀏覽器端是不知道我們服務器端對這個請求內部轉發(fā)處理了多少次。 并且無論我們服務器內部轉發(fā)了多少次,前端瀏覽器都僅僅只會認為僅僅只轉發(fā)了一次,也就是僅僅發(fā)送了一次請求 。因為我們服務器端雖然進行了轉發(fā)但是,瀏覽器的地址欄上的請求路徑的地址是沒有改變的(還是初始的請求路徑)

轉發(fā):是可以將 一個Servlet 類當中的信息轉發(fā)到另一個 Servlet 當中去的,可以實現(xiàn) Servlet 數(shù)據的共享,需要用到 請求域
注意: 請求域的作用域(請求域當中存儲的信息),只在一次 請求 范圍內有效。而轉發(fā)機制的特點決定了可以實現(xiàn)請求域的共享:因為無論服務器內部轉發(fā)了多少次,前端瀏覽器都只視為是一次請求。
轉發(fā)機制,將AServlett 類當中的信息轉發(fā)到 BServlet 當中去
package com.RainbowSea.servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設置,在瀏覽器上響應的格式類型
Date nowTime = new Date(); // 創(chuàng)建當前時間的 Date 對象
// 將 nowTime 的數(shù)據存儲(綁定)到請求域當中
request.setAttribute("sysTime",nowTime);
// 第一步: 獲取到轉發(fā)對象,注意:/ 開始,不家項目名 , / + 對應跳轉的 Servlet 當中的 web.xml 當中的url映射的路徑
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/B");
// 第二步: 調用轉發(fā)器的forward方法完成跳轉/轉發(fā)
requestDispatcher.forward(request,response);
}
}package com.RainbowSea.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設置,在瀏覽器上響應的格式類型
response.setContentType("text/html;charSet=utf-8");
PrintWriter writer = response.getWriter();
// 取出請求域當中的數(shù)據: 這里的name值與上面setAttribute(String name,Object obj) 保持一致。
Object sysTime = request.getAttribute("sysTime");
writer.println("sysTime = " + sysTime); // 顯示到瀏覽器頁面當中的數(shù)據
}
}

轉發(fā)的下一個資源必須是一個Servlet嗎 ?
不一定,只要是Tomcat服務器當中的合法資源,都是可以轉發(fā)的。例如:html....
舉例:轉發(fā)一個html文件
注意: 如果對應的不是 Servlet ,默認是從項目的中的web目錄開始的,如果是轉發(fā)web的目錄下的子目錄的話,需要指定對應的子目錄的文件。

package com.RainbowSea.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 轉發(fā)的下一個資源不一定是Servlet 資源,
// 只要是Tomcat服務器當中合法的資源,都是可以轉發(fā)的,例如: html...
// 注意:轉發(fā)的時候,路徑的寫法要注意,轉發(fā)的路徑以 “/” 開始,不加項目名
// 默認是從項目的中的web目錄開始的,如果是轉發(fā)web的目錄下的子目錄的話,需要指定對應的子目錄
// 如下是含有子目錄的 / 表示 web目錄
request.getRequestDispatcher("/test/test.html").forward(request,response);
}
}
2. Redirect重定向
重定向: 是指當瀏覽器請求一個 URL時,服務器返回一個重定向指令,告訴瀏覽器地址已經變了,麻煩使用新的URL再重新發(fā)送新請求。
重定向有兩種: 一種是302響應,稱為臨時重定向,一種是301響應,稱為永久重定向。兩者的區(qū)別是,如果服務器發(fā)送301永久重定向響應,瀏覽器會緩存/hi到/hello這個重定向的關聯(lián),下次請求/hi的時候,瀏覽器就直接發(fā)送/hello請求了。
說明: 所謂的重定向是將新的路徑交給瀏覽器的地址欄上,然后自動執(zhí)行的,而前端的信息獲取是需要指明項目名的,所以:注意:重定向 response.sendRedirect("/項目名/xxx/xx");的跳轉路徑是需要寫明項目名的 。
// 下面這種是 302 響應,臨時重定向
// 注意:路徑上要加一個項目名。為什么?
// 瀏覽器發(fā)送請求,請求路徑上是需要添加項目名的。
// 以下這一行代碼會將請求路徑“/oa/dept/list”發(fā)送給瀏覽器
// 瀏覽器會自發(fā)的向服務器發(fā)送一次全新的請求:/oa/dept/list
response.sendRedirect("/oa/dept/list");HttpServletResponse提供了快捷的redirect()方法實現(xiàn)302重定向。如果要實現(xiàn)301永久重定向,可以這么寫:
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301
response.setHeader("Location", "/hello");舉例: 瀏覽器向 AServlet 發(fā)送請求,AServlet 將該請求 “重定向”給了 BServlet。重定向一個新的URL地址,告訴瀏覽器發(fā)送的處理請求的URL地址改變了,將該請求發(fā)送到該重定向的URL中去,也就是這里的BServlet。
package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 重定向的路徑 需要加項目名
response.sendRedirect("/servlet12/b");
// 可以使用 request.getContextPath() 獲取到項目名(也就是項目名的根路徑),注意該返回的路徑是帶 “/”的 /項目名
// 所以不要多寫了 “/”
// response.sendRedirect(request.getContextPath()+"/b");
}
}package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設置瀏覽器端顯示響應的,格式類型,以及字符集
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("<h2> 這里是BServlet 的響應處理 </h2>");
}
} // 重定向: (重新定方向)
//response.sendRedirect("/項目名/");
// 重定向時的路徑當中需要以項目名開始,或者說需要添加項目名的
// 因為所謂的重定向是將新的路徑交給瀏覽器的地址欄上,然后自動執(zhí)行的,而前端的信息獲取是需要指明項目名的
// response對將這個路徑: /servlet10/B 響應給了瀏覽器了。
// 瀏覽器又自發(fā)的向服務器發(fā)送了一個全新的請求: http://127.0.0.1:8080/servlet12/a
// 所以瀏覽器一共發(fā)送了 "兩次"請求:
// 第一次請求: http://127.0.0.1:8080/servlet12/a
// 第二次請求: http://127.0.0.1:8080/servlet12/b
// 最終瀏覽器地址欄上顯示的地址信息當然就是最后那一次請求的地址,所以重定向會導致瀏覽器
// 地址欄上的地址發(fā)生改變。
// 但是重定向是一次新的請求,是無法獲取到請求域當中(只在一次請求中有效)信息的
// 重定向操作是由:跳轉到哪個資源,是由瀏覽器的地址欄說的算的。
// 注意: request.getContextPath()返回的項目名的根路徑是帶有了 "/"了的
response.sendRedirect(request.getContextPath()+"/B");
重定向: 瀏覽器是知道,實際轉發(fā)了多少次請求的。

注意:重定向是“重定向幾次,就會發(fā)送幾次請求,導致的結果就是,重定向無法使用 請求域,因為請求域的作用范圍是再一次請求當中的,重定向無法實現(xiàn) Servlet 之間的數(shù)據共享。
舉例如下:定義了一個 名為 User 類的JavaBean,在 AServlet 當中 new 一個 User 對象,并存儲到AServlet請求域當中,存儲好以后,重定向給 BServlet ,在BServlet 當中想將存儲到 AServlet 請求域當中的數(shù)據取出來,這是不行的,因為請求域只在一次請求中有效,而這里重定向了一次,就會多一次請求也就是兩次請求。無法獲取到AServlet 請求域當?shù)拇鎯Φ臄?shù)據。
package com.RainbowSea.servlet;
import java.io.Serializable;
import java.util.Objects;
/**
* 1. 一個普通的Javabean
* 2. 什么是javabean
* Java是咖啡,bean 是豆子
* javabean 咖啡豆
* 咖啡是由咖啡豆研磨而成的,寓意:是Java程序是由一個一個的javabean組成的
* 3. 一個javaBean一般是有規(guī)范的
* 有無參數(shù)的構造方法
* 屬性私有化
* 對外提供 get/set()方法
* 重寫toString()
* 重寫hashCode() + equals
* 實現(xiàn)java.io.Serializable 接口 可序列化的
*/
public class User implements Serializable {
private String id;
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(getId(), user.getId()) && Objects.equals(getName(), user.getName());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getName());
}
public User() {
}
public User(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 創(chuàng)建 User 對象
User user = new User("001","張三");
// 將 user 對象存儲到 請求域當中
request.setAttribute("userObj",user);
// 重定向的路徑 需要加項目名
response.sendRedirect("/servlet12/b");
// 可以使用 request.getContextPath() 獲取到項目名(也就是項目名的根路徑),注意該返回的路徑是帶 “/”的 /項目名
// 所以不要多寫了 “/”
// response.sendRedirect(request.getContextPath()+"/b");
}
}package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 無法取出 AServlet 請求域當中的數(shù)據
Object userObj = request.getAttribute("userObj");
// 設置瀏覽器端顯示響應的,格式類型,以及字符集
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("從AServlet 獲取的數(shù)據:" + userObj);
}
}
重定向:除了重定向 Servlet 資源以外,還可以重定向其他資源,比如 html...等等只要是服務器當中合法的資源都可以。
舉例:AServlet 重定向一個名為 index.html 的資源
package com.RainbowSea.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 重定向一個名為 index.html 的資源
// request.getContextPath() 返回的是該webapp的項目的根路徑:也就是/項目名,注意是帶 “/”的,不要多寫了
response.sendRedirect(request.getContextPath()+"/index.html");
}
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>Hello World</h1>
<h1>你好世界</h1>
</body>
</html>
3. 轉發(fā)使用不當?shù)奈:Γ恨D發(fā)刷新問題
說明: 由于轉發(fā)的機制的特點:無論轉發(fā)了服務器內部 轉發(fā) 多少次,瀏覽器都視為是請求了一次,而且還是原來(最初的那一次請求,不是轉發(fā)之后到的頁面的請求)。這樣的特征,如果使用不當?shù)脑?,就會存?一個刷新問題:就是你服務器內部雖然發(fā)送了轉發(fā)性質的跳轉到了一個新的頁面,服務器內部轉發(fā)到一個新的頁面成功后,你在瀏覽器端重新刷新的話,還是對最初的一個URL請求刷新的(因為轉發(fā)是不會改變?yōu)g覽器地址欄上的 URL 地址的)。
舉例: 我們在 StudentServlet 中執(zhí)行向數(shù)據庫的一張名為 studnet 表插入一條記錄的操作。插入成功跳轉到一個名為 succeed.html的頁面,插入失敗跳轉到一個名為 error.html失敗的頁面。然后我們對跳轉到 succeed.html* 頁面后,在瀏覽器 執(zhí)行刷新 操作看看會導致一個什么樣的結果 ?
準備工作: 創(chuàng)建一個數(shù)據表,并插入一些數(shù)據
CREATE TABLE studnet (
`no` VARCHAR(255),
`name` VARCHAR(255)
);
INSERT INTO studnet (`no`,`name`) VALUES('1','張三'),('2','李四');
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class StudentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
/*
思路: 獲取到前端的提交的數(shù)據
連接數(shù)據庫,操作數(shù)據庫
*/
// 獲取到前端提交的數(shù)據
request.setCharacterEncoding("UTF-8");
String no = request.getParameter("no");
String name = request.getParameter("name");
Connection connection = null;
PreparedStatement preparedStatement = null;
// 表示影響數(shù)據庫的行數(shù)
int count = 0;
try {
// 1. 連接數(shù)據庫,這里的DBUtil.getConnection(); 是我寫的一個連接數(shù)據庫的工具類,大家不用太在意
connection = DBUtil.getConnection();
// 2. 獲取操作數(shù)據庫對象,預編譯sql語句,注意測試sql是否存在錯誤
// 注意: ? 不要加 '', ""單雙引號,不然無法識別到該占位符的
String sql = "INSERT INTO studnet (`no`,`name`) VALUES(?,?)";
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符,真正執(zhí)行sql語句
preparedStatement.setString(1,no);
preparedStatement.setString(2,name);
count = preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 4. 釋放資源
DBUtil.close(connection,preparedStatement,null);
}
if(count == 1) {
// 添加成功
// 先用 轉發(fā)機制 ,轉發(fā)服務器內部,不要加項目名
request.getRequestDispatcher("/succeed.html").forward(request,response);
} else {
request.getRequestDispatcher("/error.html").forward(request,response);
}
}
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加成功</title>
</head>
<body>
<h1>添加成功</h1>
</body>
</html><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加失敗</title>
</head>
<body>
<h1>添加失敗</h1>
</body>
</html>實驗效果如下:


但是,如果我們這時候,在瀏覽器端點擊刷新,這里我們,點擊了 3次刷新。導致的結果如下:

優(yōu)化: 這里我們將轉發(fā) 修改為 重定向 就沒有這樣的問題了,因為重定向是會改變?yōu)g覽器地址欄上的 URL 地址的(為最后我們重定向(跳轉)的頁面的URL地址)。
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class StudentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
/*
思路: 獲取到前端的提交的數(shù)據
連接數(shù)據庫,操作數(shù)據庫
*/
// 獲取到前端提交的數(shù)據
request.setCharacterEncoding("UTF-8");
String no = request.getParameter("no");
String name = request.getParameter("name");
Connection connection = null;
PreparedStatement preparedStatement = null;
// 表示影響數(shù)據庫的行數(shù)
int count = 0;
try {
// 連接數(shù)據庫
connection = DBUtil.getConnection();
// 注意: ? 不要加 '', ""單雙引號,不然無法識別到該占位符的
String sql = "INSERT INTO studnet (`no`,`name`) VALUES(?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,no);
preparedStatement.setString(2,name);
count = preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 釋放資源
DBUtil.close(connection,preparedStatement,null);
}
if(count == 1) {
// 添加成功
// 先用 轉發(fā)機制 ,轉發(fā)服務器內部,不要加項目名
// request.getRequestDispatcher("/succeed.html").forward(request,response);
// 優(yōu)化修改為重定向:重定向前端需要指明 項目名(/項目的根路徑)
// request.getContextPath() 該方法可以獲取到: "/項目的根路徑",注意是帶有 / 的,所以不要多寫了 /
response.sendRedirect(request.getContextPath()+"/succeed.html");
} else {
// request.getRequestDispatcher("/error.html").forward(request,response);
response.sendRedirect(request.getContextPath()+"/error.html");
}
}
}
4. 轉發(fā) 與 重定向的區(qū)別
代碼上的區(qū)別:
轉發(fā) :轉發(fā)的路徑 不要 寫項目名(項目的根路徑)
// 獲取請求轉發(fā)器對象
RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
// 調用請求轉發(fā)器對象的forward方法完成轉發(fā)
dispatcher.forward(request, response);
// 合并一行代碼
request.getRequestDispatcher("/dept/list").forward(request, response);
// 轉發(fā)的時候是一次請求,不管你轉發(fā)了多少次。都是一次請求。
// AServlet轉發(fā)到BServlet,再轉發(fā)到CServlet,再轉發(fā)到DServlet,不管轉發(fā)了多少次,都在同一個request當中。
// 這是因為調用forward方法的時候,會將當前的request和response對象傳遞給下一個Servlet。重定向 :重定向的路徑,需要 寫項目名(項目的根路徑)
response.sendRedirect("/servlet12/b");
// 可以使用 request.getContextPath() 獲取到項目名(也就是項目名的根路徑),注意該返回的路徑是帶 “/”的 /項目名,所以不要多寫了 “/”
response.sendRedirect(request.getContextPath()+"/index.html");形式上有什么區(qū)別 ?
轉發(fā)(一次請求)
在瀏覽器地址欄上發(fā)送的請求是:http://localhost:8080/servlet10/a ,最終請求結束之后,瀏覽器地址欄上的地址還是這個。沒變。
重定向(兩次請求)
在瀏覽器地址欄上發(fā)送的請求是:http://localhost:8080/servlet10/a ,最終在瀏覽器地址欄上顯示的地址是:http://localhost:8080/servlet10/b(也就是最后重定向的地址)
轉發(fā)和重定向的本質區(qū)別 ?
轉發(fā):是由WEB服務器來控制的。A資源跳轉到B資源,這個跳轉動作是Tomcat服務器內部完成的。所以無論 服務器轉發(fā)了多少次,而我們前端也就是瀏覽器端是不知道我們服務器端對這個請求內部轉發(fā)處理了多少次。 并且無論我們服務器內部轉發(fā)了多少次,前端瀏覽器都僅僅只會認為僅僅只轉發(fā)了一次,也就是僅僅發(fā)送了一次請求 。因為我們服務器端雖然進行了轉發(fā),但是瀏覽器的地址欄上的請求路徑的地址是沒有改變的(還是初始的請求路徑)
重定向:是瀏覽器完成的。具體跳轉到哪個資源,是瀏覽器說了算。當瀏覽器請求一個 URL時,服務器返回一個重定向指令,告訴瀏覽器要處理該請求的URL地址已經變了,麻煩使用新的URL再重新發(fā)送新請求。所以,前端瀏覽器是知道我們重定向了多少次的,而且重定向是“重定向幾次,就會發(fā)送幾次請求”。
相同點: 無論是 “轉發(fā)”還是 “重定向”都可以跳轉到另外一個資源當中,都是不僅僅是 Servlet 資源,也可以是其他的服務器上合法的資源比如:html等等。
優(yōu)缺點上的區(qū)別:
轉發(fā): 可以通過請求域存儲數(shù)據的方式,實現(xiàn)多個Servlet 數(shù)據的共享。因為:多少次轉發(fā)都是只視為一次請求。但是轉發(fā)存在刷新問題 。
重定向:沒有刷新問題,但是無法通過請求域存儲數(shù)據的方式,實現(xiàn)多個Servlet 數(shù)據的共享。因為:“重定向幾次,就會發(fā)送幾次請求”。而請求域只在一次請求范圍有效。
轉發(fā)與重定向 舉例圖示上的描述:
轉發(fā):


重定向:


5. “重寫向”與“轉發(fā)”的合理選擇
- 如果在上一個Servlet當中向request域當中綁定了數(shù)據,希望從下一個Servlet當中把request域里面的數(shù)據取出來,使用轉發(fā)機制。
- 剩下所有的請求均使用重定向。(重定向使用較多。)
重定向的目的是當Web應用升級后,如果請求路徑發(fā)生了變化,可以將原來的路徑重定向到新路徑,從而避免瀏覽器請求原路徑找不到資源。
6. 總結:
轉發(fā) :指內部轉發(fā)。當一個Servlet處理請求的時候,它可以決定自己不繼續(xù)處理,而是轉發(fā)給另一個Servlet處理。
轉發(fā)是由WEB服務器來控制的。A資源跳轉到B資源,這個跳轉動作是Tomcat服務器內部完成的 ,而我們前端也就是瀏覽器端是不知道我們服務器端對這個請求內部轉發(fā)處理了多少次。 并且無論我們服務器內部轉發(fā)了多少次,前端瀏覽器都僅僅只會認為僅僅只轉發(fā)了一次,也就是僅僅發(fā)送了一次請求 。因為我們服務器端雖然進行了轉發(fā)但是,瀏覽器的地址欄上的請求路徑的地址是沒有改變的(還是初始的請求路徑) 編寫的轉發(fā)路徑是不要加項目名的。
重定向: 是指當瀏覽器請求一個 URL時,服務器返回一個重定向指令,告訴瀏覽器地址已經變了,麻煩使用新的URL再重新發(fā)送新請求。
- 重定向有兩種: 一種是302響應,稱為臨時重定向,一種是301響應,稱為永久重定向。兩者的區(qū)別是,如果服務器發(fā)送301永久重定向響應,瀏覽器會緩存
/hi到/hello這個重定向的關聯(lián),下次請求/hi的時候,瀏覽器就直接發(fā)送/hello請求了。 - 說明: 所謂的重定向是將新的路徑交給瀏覽器的地址欄上,然后自動執(zhí)行的,而前端的信息獲取是需要指明項目名的,所以:注意:重定向
response.sendRedirect("/項目名/xxx/xx");的跳轉路徑是需要寫明項目名的 。
注意:轉發(fā)機制存在的一個刷新問題。
轉發(fā) 與 重定向的區(qū)別
到此這篇關于JavaWeb中轉發(fā)與重定向的區(qū)別小結的文章就介紹到這了,更多相關JavaWeb 轉發(fā)與重定向內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Javaweb-HttpServletResponse的sendRedirectch重定向方式
- 詳解Java從后臺重定向(redirect)到另一個項目的方法
- 關于Javaweb的轉發(fā)和重定向詳解
- Java通過httpclient比較重定向和請求轉發(fā)
- Java請求轉發(fā)和請求重定向區(qū)別詳解
- JavaWeb中請求轉發(fā)和請求重定向的區(qū)別以及使用
- Javaweb請求轉發(fā)及重定向實現(xiàn)詳解
- java 轉發(fā)和重定向區(qū)別及實例代碼
- java轉發(fā)和重定向的區(qū)別
- Java中forward轉發(fā)與redirect重定向的區(qū)別
相關文章
java web在高并發(fā)和分布式下實現(xiàn)訂單號生成唯一的解決方案
這篇文章主要介紹了java web在高并發(fā)和分布式下實現(xiàn)訂單號生成唯一的解決方案,需要的朋友可以參考下2017-11-11
在Java的Hibernate框架中對數(shù)據庫數(shù)據進行查詢操作
這篇文章主要介紹了Java的Hibernate框架中對數(shù)據庫數(shù)據進行查詢操作的方法,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12
Java中的BlockingQueue阻塞隊列原理以及實現(xiàn)詳解
這篇文章主要介紹了Java中的BlockingQueue阻塞隊列原理以及實現(xiàn)詳解,在最常見的使用到這個阻塞隊列的地方,就是我們耳熟能詳?shù)木€程池里面了,作為我們線程池的一大最大參與者,也是AQS的一個具體實現(xiàn),需要的朋友可以參考下2023-12-12

