Request Dispatcher 的 forward () 和 include () 有什么区别?

RequestDispatcher(请求调度器)是 Servlet/JSP 中用于在服务器内部转发 / 包含资源的核心接口,forward()(转发)和include()(包含)是其两个核心方法,本质都是服务器内部操作(客户端无感知),但执行逻辑、响应处理、使用场景差异显著:

核心区别对比表:

维度 forward ()(请求转发) include ()(请求包含)
执行逻辑 将请求完全移交到目标资源,当前资源停止输出; 执行目标资源并获取其输出,再回到当前资源继续输出;
响应控制权 目标资源完全接管响应(当前资源的输出会被忽略); 当前资源保留响应控制权,目标资源的输出嵌入当前响应;
输出内容 仅目标资源的输出发送到客户端; 当前资源 + 目标资源的输出合并后发送到客户端;
调用时机 需在当前资源未输出任何内容前调用(否则抛异常); 可在当前资源任意位置调用(即使已有输出);
响应状态码 / 头信息 由目标资源设置(当前资源的设置会被覆盖); 由当前资源设置(目标资源的设置会被忽略);
适用场景 业务逻辑跳转(如登录成功跳转到首页); 页面组件复用(如包含页眉、页脚、公共导航);
等价 JSP 标签 <jsp:forward> <jsp:include>

具体行为说明:

(1)forward ()(请求转发)
  • 执行流程:

    1. 客户端发送请求到 A.jsp/Servlet;
    2. A 调用forward(),服务器将请求对象(request)、响应对象(response)传递给 B.jsp/Servlet;
    3. A 停止所有输出,B 完全处理请求并生成响应;
    4. 服务器将 B 的响应返回给客户端(地址栏仍显示 A 的 URL)。
  • 关键限制:调用forward()前,当前资源不能有任何内容输出到客户端(包括空白字符、HTML 标签),否则会抛出IllegalStateException(响应已提交)。

  • 示例:

    1
    2
    3
    // Servlet中调用forward
    RequestDispatcher rd = request.getRequestDispatcher("/index.jsp");
    rd.forward(request, response);
(2)include ()(请求包含)
  • 执行流程:

    1. 客户端发送请求到 A.jsp/Servlet;
    2. A 执行到include()时,服务器将请求 / 响应传递给 B.jsp/Servlet,执行 B 并获取其输出;
    3. B 的输出嵌入到 A 的响应中,A 继续执行剩余逻辑;
    4. 服务器将 A+B 的合并响应返回给客户端。
  • 关键特点:即使 A 已有输出,include()仍可正常执行;B 的响应头会被忽略,仅保留输出内容。

  • 示例:

    1
    2
    3
    4
    5
    // JSP中通过脚本调用include(等价于<jsp:include>)
    <%
    RequestDispatcher rd = request.getRequestDispatcher("/footer.jsp");
    rd.include(request, response);
    %>

核心总结:

  • forward()是 “跳转”:目标资源替代当前资源,仅返回目标的响应;
  • include()是 “嵌入”:目标资源的内容嵌入当前资源,返回合并的响应;
  • 两者均共享同一个request对象(可传递请求参数 / 属性),但forward()更侧重逻辑跳转,include()更侧重页面组件复用。