目录
概述
请求转发
逻辑图
测试代码
总结
响应重定向
逻辑图
测试代码
总结
完!
概述
什么是请求转发和响应重定向?
请求转发和响应重定向,是 web 应用中,间接访问项目资源的两种手段,也是 Servlet 控制页面跳转的两种手段
请求转发:通过 HTTPServletRequest 实现
响应重定向:通过 HttpServletResoponse 实现
举个栗子:
请求转发:A 找 B 借钱,B 没有,B 找到 C,让 C 直接把钱打到了 A 的账户上,A 只知道自己找到 B 借钱~
响应重定向:A 找 B 借钱,B 没有,B 告诉 A,你去找 ,A 又找到 C,C 把钱借给了 A~
请求转发
逻辑图
客户端通过 HTTP 协议,向部署在 Tomcat 服务器上的 app 应用,发送了请求(比如访问某个 url),Tomcat 接收到请求后,会将请求报文,封装为 HttpServletRequest 对象(即图中的 request),同时 Tomcat 也会创建 HttpServletResponse 对象(即图中的 response)用于后续处理响应
Tomcat 根据 request 中的 url,匹配 app 中对应的 Servlet(图中的 ServletA),将 request 和 response 传递给 ServletA 进行处理。
在 ServletA 处理过程中,通过请求转发的机制(调用 request.getRequestDispatcher("目标路径").forward(request, response)),把当前的 request 和 response 转交给 ServletB 继续处理。(注意!!! 这一步过程中,是在服务器内部完成的,客户端完全感知不到~ 整个过程属于同一次 HTTP 请求)
ServletB 拿到 ServletA 传来的 resquest 和 response 后,执行自己的业务,最终再通过 response 组装响应报文
Tomcat 将响应报文相应给客户端~
总结:一次请求,多个 Servlet 接力处理,最后统一相依~
测试代码
代码还需要像之前,添加 Tomcat 依赖,项目组件,设置 Tomcat 依赖~ 此处省略~
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 测试请求转发*/
@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletA 执行了~");// 请求转发给 ServletB// 获得请求转发器RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");// 让请求转发器做出转发动作requestDispatcher.forward(req,resp);}
}
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 测试请求转发*/
@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletB 执行了~");}
}
请求转发也可以携带参数数据过去~
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 测试请求转发*/
@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletA 执行了~");String money = req.getParameter("money");System.out.println("servletA 获得参数 money = " + money);// 请求转发给 ServletB// 获得请求转发器RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");// 让请求转发器做出转发动作requestDispatcher.forward(req,resp);}
}
package com.zzz.servlet;import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/06 21:30* @description: 测试请求转发*/
@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("ServletB 执行了~");String money = req.getParameter("money");System.out.println("servletB 获得参数 money = " + money);}
}
请求转发,除了能从 servletA 中转发到 servletB 外,还能转发到静态页面下,还能转发到 WEB-INF 下面的保护资源!!!
但是,不能直接在 forward 中跳转到项目外的完整的 URL 地址中
总结
1. 请求转发是通过 HttpServletRequest 对象获取请求转发器实现的
2. 请求转发是服务器内部的行为,对客户端是屏蔽的
3. 客户端只发送了一次请求,即,客户端地址栏不变
4. 服务端只产生了一对请求和响应对象(request 和 response),这一对请求和响应对象,会继续传递给下一个资源
5. 因为全程只有一个 HttpServletRequest 对象,所以请求中的参数可以传递,请求域中的数据也可以传递
6. 请求转发可以转发给其他的 Servlet 动态资源,也可以转发给一些静态资源,以实现页面跳转
7. 请求转发可以转发给 WEB-INF 下受保护的资源
8. 请求转发不能转发到本项目以外的其他外部资源
~~~
响应重定向
逻辑图
第一次交互:客户端 -> ServletA(触发重定向)
1. 客户端发请求:
客户端先发起第一次 HTTP 请求(比如访问 ServletA 的URL),Tomcat 接收到后,创建 request(请求对象,封装请求数据)和 response(响应对象,用于构建返回给客户端的内容),并将这两个对象传递给 ServletA 处理
2. ServletA 处理 & 触发重定向
ServletA 中编写重定向逻辑(response.sendRedirect("Servlet 的 URL"))。执行后,Tomcat 会通过 response 给客户端发送一个 3xx(如 302 )的状态码,同时在响应头中带上 Location:ServletB 的 URL,告诉客户端,让客户端去新的地址重新发送请求。
第二次交互:客户端 -> ServletB(重定向后的新请求)
3. 客户端自动发起新请求:
客户端(浏览器)受到 302 的响应后,自动发起第二次 HTTP 请求,目标就是 Location 里的 ServletB 的地址。此时,Tomcat 再次创建新的 request 和 response,传递给 ServletB 处理
4. ServletB 处理 & 返回响应
ServletB 处理业务逻辑,通过 response 构建实际的响应内容,Tomcat 将响应返回给客户端。
理解:为什么叫“重定向”
两次独立请求:重定向涉及到 客户端发起的两次 HTTP 请求,第一次是根据输入的 URL 到 ServletA,第二次则是自动到 ServletB,两次请求的 request / response 完全独立~(数据完全不共享~)
客户端可见跳转:因为是浏览器自动发起新请求,地址栏 URL 会变成 ServletB 的地址,用户可以直观的看到“跳转”过程。
总结:
重定向就是”让客户端换个地址重新请求“的过程,通过 Tomcat 转发响应指令(302 + Location),由浏览器自动触发第二次请求。
对比请求转发(一次请求,服务器内部调度),重定向更强调“客户端参与,两次请求”。
测试代码
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/07 00:14* @description:*/
@WebServlet("/servlet1")
public class Servlet1 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 接收用户请求System.out.println("Servlet1 执行了");// 响应重定向 设置响应状态码为 302 同时设置 Location 响应头resp.sendRedirect("servlet2");
// resp.sendRedirect("a.html");
// resp.sendRedirect("/WEB-INF/b.html");
// resp.sendRedirect("https://www.baidu.com");}
}
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/07 00:15* @description:*/
@WebServlet("/servlet2")
public class Servlet2 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("servlet2 执行了");}
}
响应重定向,无法将参数携带过去,无法访问 WEB-INF 下的资源,但目标资源可以是外部资源完整 URL
总结
1. 响应重定向通过 HttpServletResponse 对象的 sendRedirect 方法实现
2. 响应重定向是服务端通过 302 响应码和路径,告诉客户端自己去找资源,是在服务端的挺行下的客户端的行为
3. 客户端至少发送了两次请求,客户端的地址栏会发生变化
4. 服务端产生了多对请求和响应对象(request 和 response),且请求和响应对象并不会传递给下一个资源
5. 全程产生了多个 HttpServletRequet 对象,所以请求参数不可以传递,请求域中的数据也不可以传递
6. 重定向可以是其他 Sevlet 动态资源,也可以是一些静态资源以实现页面跳转
7. 重定向不可以访问 WEB-INF 中保护的资源
8. 重定向可以到本项目外的外部资源
~~~
补充:当两种方式都能实现请求跳转的时候,我们一般优先使用响应重定向!