JavaWeb Servlet请求转发与响应重定向教程

请求转发与响应重定向教程

1 概述

请求转发和响应重定向是 Web 应用中实现资源间接访问、控制页面跳转的两种核心手段。

  • 请求转发:通过 HttpServletRequest 对象实现,是服务器内部行为

    • 生活举例:张三找李四借钱,李四没钱,李四直接找王五借,最后把钱给张三(张三全程只找了李四一次)。
  • 响应重定向:通过 HttpServletResponse 对象实现,是客户端行为

    • 生活举例:张三找李四借钱,李四没钱,让张三自己去找王五借(张三又单独找了王五)。

2 请求转发

请求转发特点(核心)

  1. 服务器内部行为,客户端地址栏不变

  2. 客户端只发送1 次请求,服务端只有 1 对 Request/Response 对象。

  3. 请求参数、请求域数据可以传递

  4. 可以访问 WEB\-INF 下的受保护资源。

  5. 不能访问项目外部资源。

请求转发代码示例

1. ServletA(转发发起方)

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;

@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数(演示参数传递)
        String username = req.getParameter("username");
        System.out.println("ServletA 收到参数:username = " + username);

        // 2. 向请求域中存入数据(演示域数据传递)
        req.setAttribute("reqMsg", "这是ServletA存入请求域的数据");

        // 3. 获取请求转发器,转发给 ServletB
        // 也可以转发给静态资源:req.getRequestDispatcher("welcome.html")
        // 也可以转发给WEB-INF下资源:req.getRequestDispatcher("WEB-INF/secret.html")
        req.getRequestDispatcher("servletB").forward(req, resp);
    }
}

2. ServletB(转发目标方)

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;
import java.io.PrintWriter;

@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取 ServletA 传递的请求参数
        String username = req.getParameter("username");
        System.out.println("ServletB 收到参数:username = " + username);

        // 2. 获取 ServletA 存入请求域的数据
        String reqMsg = (String) req.getAttribute("reqMsg");
        System.out.println("ServletB 收到域数据:" + reqMsg);

        // 3. 给客户端响应
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.write("ServletB 响应成功!<br>");
        writer.write("收到参数:username = " + username + "<br>");
        writer.write("收到域数据:" + reqMsg);
    }
}

测试步骤

启动项目,浏览器访问:

http://localhost:8080/你的项目名/servletA?username=zhangsan

观察:

  • 地址栏保持 ****/servletA**** 不变

  • 页面显示 ServletB 的响应,且能看到参数和域数据。

3 响应重定向

响应重定向特点(核心)

  1. 客户端行为,服务端通过 302 响应码 + 路径,让客户端重新请求新资源。

  2. 客户端发送至少 2 次请求,地址栏会变化

  3. 请求参数、请求域数据不能传递(因为是新的 Request 对象)。

  4. 不能访问 WEB\-INF 下的受保护资源。

  5. 可以访问项目外部资源(如百度、尚硅谷官网)。

响应重定向代码示例

1. ServletA(重定向发起方)

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;

@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数(重定向后无法传递)
        String username = req.getParameter("username");
        System.out.println("ServletA 收到参数:username = " + username);

        // 2. 向请求域中存入数据(重定向后无法传递)
        req.setAttribute("reqMsg", "这是ServletA存入请求域的数据");

        // 3. 响应重定向到 ServletB
        // 也可以重定向到外部资源:resp.sendRedirect("http://www.atguigu.com");
        resp.sendRedirect("servletB");
    }
}

2. ServletB(重定向目标方)

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;
import java.io.PrintWriter;

@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 尝试获取参数(重定向后为 null)
        String username = req.getParameter("username");
        System.out.println("ServletB 收到参数:username = " + username);

        // 2. 尝试获取域数据(重定向后为 null)
        String reqMsg = (String) req.getAttribute("reqMsg");
        System.out.println("ServletB 收到域数据:" + reqMsg);

        // 3. 给客户端响应
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.write("ServletB 响应成功!<br>");
        writer.write("收到参数:username = " + username + "<br>");
        writer.write("收到域数据:" + reqMsg);
    }
}

测试步骤

启动项目,浏览器访问:

http://localhost:8080/你的项目名/servletA?username=zhangsan

观察:

  • 地址栏变成 ****/servletB

  • 页面显示参数和域数据均为 null

9.4 核心区别对比表

对比维度 请求转发 响应重定向
请求次数 1 次 至少 2 次
地址栏变化 不变 变化
参数 / 域数据传递 可以传递 不能传递
访问 WEB-INF 资源 可以 不可以
访问外部资源 不可以 可以
行为主体 服务器 客户端

9.5 常见问题:GET/POST 支持与参数传递

1. 请求转发:GET/POST 都完美支持

  • 无论客户端是 GET 还是 POST 请求 ServletA,转发到 ServletB 后,请求方法保持不变(ServletA 是 POST,ServletB 收到的也是 POST)。

  • 请求参数(无论是 URL 后的 GET 参数,还是表单的 POST 参数),都能完整传递

2. 响应重定向:GET/POST 有细节

  • 重定向后的请求方法默认是 GET

    • 如果客户端是 POST 请求 ServletA,重定向到 ServletB 后,ServletB 收到的是 GET 请求。

    • 如果客户端是 GET 请求 ServletA,重定向后还是 GET。

  • 参数传递技巧

    • 如果一定要在重定向时传参,可以手动拼在 URL 后面:

      resp.sendRedirect("servletB?username=" + username);
      
    • 但注意:URL 传参有长度限制,且敏感数据会暴露在地址栏。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容