转发VS重定向

转发VS重定向

1-参考文档:

https://blog.csdn.net/weixin_51418964/article/details/123454677

https://blog.csdn.net/pison007/article/details/112323155


2-转发(forward)

一种在服务器内部的资源跳转方式。

服务端转发

2.1-实现步骤

  1. 通过 request 对象获取请求转发器对象:RequestDispatcher,getRequestDispatcher(String path)
  2. 然后使用 RequestDispatcher 对象来进行转发:forward(ServletRequest request, ServletResponse response)
req.getRequestDispatcher("/requestTest").forward(req, resp);

注意:这里是给服务器用的,所以不需要获取虚拟目录(/项目名),即 request.getContextPath();

2.2-图解

image-20221026105452387.

解释:客户端浏览器发送请求到 Request1,Request1 转发请求到 Request2,并且 Request1 和 Request2 共享 这次 request 请求中的 request 域数据。

2.3-代码示例

2.3.1-请求转发

设置一个数据域,并且把它转发到 request2

@WebServlet("/req1")
public class 请求转发 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("name", "软柠柠吖");
        req.getRequestDispatcher("/req2").forward(req, resp);
        System.out.println("request1 被访问了。。");
    }
}

2.3.2-共享数据

获取 Request1 中的数据域,并打印信息。

@WebServlet("/req2")
public class 共享数据 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object name = req.getAttribute("name");
        System.out.println("name = " + name);
        System.out.println("Request2 被访问了。。。");
    }
}

2.3.3-结果

当我们在浏览器中输入 http://localhost:8080/project/req1 并敲击回车后,可以看到:

  1. req2 居然输出了 req1 的 “软柠柠吖”。
  2. req2 和 req1 同时被访问了,而 req2 先被访问,req1 后被访问。

image-20221026111257882.

2.4-特点

  1. 抓包分析后,发现虽然访问到了 2 个 servlet,但是实际上却是一次请求

image-20221026113903992.

  1. 当我们把要转发的资源 /req2 换成 同在一个服务器但是不同的项目中的资源 /req3 发现并不能实现转发(404 Not Found),这说明了只能转发到当前服务器的内部的同一个项目的资源
@WebServlet("/req3")
public class 同一个服务器但是不同项目 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object name = req.getAttribute("name");
        System.out.println("req3 name = " + name);
        System.out.println("req3 被访问了。");
    }
}
@WebServlet("/req1")
public class 请求转发 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("name", "软柠柠吖");
        req.getRequestDispatcher("/req3").forward(req, resp);
        System.out.println("request1 被访问了。。");
    }
}

image-20221026112950249.

  1. 浏览器地址栏路径不发生变化。

image-20221026113950047.

  1. 可以访问 WEB-INF 目录下的资源文件。
@WebServlet("/req1")
public class 请求转发 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/WEB-INF/web.xml").forward(req, resp);
    }
}
  • 成功访问到了 WEB-INF 下的 web.xml 文件

image-20221026194919212.

3-重定向(redirect)

另一种资源跳转方式。

客户端重定向

3.1-实现步骤(2种)

3.1.1-完整版

3.1.1.1-设置状态码为 302
resp.setStatus(302);
3.1.1.2-设置响应头
resp.setHeader("location", "/project/response2");

3.1.2-简洁版【常用

resp.sendRedirect(req.getContextPath() + "/response2");

3.2-图解

image-20221026185451550.

3.3-代码示例

3.3.1-编写 response1,将请求重定向到 response2

@WebServlet("/response1")
public class 重定向 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("redirect1~");
        /*
        resp.setStatus(302); // 设置状态码为 302(重定向)
        resp.setHeader("location", "/project2/response2"); // 设置响应头 location
         */
        // 给客户端用,需要加虚拟目录 /project2
        resp.sendRedirect("/project2/response2");
    }
}

注意:这里给客户端使用,需要加虚拟目录。即 req.getContextPath();

3.3.2-编写 response2,直接输出信息

@WebServlet("/response2")
public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("response2~~");
    }
}

3.3.3-结果

当我们输入 http://localhost:8080/project1/response1 敲击回车,发现浏览器地址会瞬间变成 http://localhost:8080/project2/response2,抓包分析发现浏览器一共发送了 2 次请求。

image-20221026190306762.

3.4-特点

  1. 地址栏发生变化。

这个不用再解释了,看上图即可~

  1. 重定向可以访问其他站点(服务器)的资源。
@WebServlet("/response1")
public class 重定向 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 重定向到百度
        resp.sendRedirect("http://www.baidu.com");
    }
}

注意:如果重定向到外部网站,必须加上 http://

image-20221026191451065.

image-20221026191722409.

  1. 重定向是两次请求。不能使用 request 对象来共享数据。

每一次浏览器发起的请求报文,都会被 Tomcat 封装到 Request 对象中。当第二次请求发出的时候,浏览器又发起了新的请求报文,Tomcat 会重新创建一个 Request 对象,去封装第二次请求报文,所以就会出现 req1 有参数,req2 无参数。

  • 给 reqest 设置 name 参数并重定向
@WebServlet("/response1")
public class 重定向 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("name", "软柠柠吖");
        Object name = req.getAttribute("name");
        resp.sendRedirect("/project2/response2");
        System.out.println("req1 name = " + name);
    }
}
  • 获取 reqest 中的 name 参数
@WebServlet("/response2")
public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object name = req.getAttribute("name");
        System.out.println("req2 name = " + name);
    }
}
  • 结果

image-20221026193541693.

  1. 无法访问 WEB-INF 目录下的资源文件

原因:由于 WEB-INF 文件夹下的 html 等资源文件会受到服务器的保护,浏览器无法直接访问。在第二次请求访问的时候就被服务器拒绝了。

@WebServlet("/response1")
public class 重定向 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/project/WEB-INF/web.xml");
    }
}

image-20221026194225155.

4-转发和重定向的区别【总结】

  1. 转发的地址栏不变,而重定向变成转发后的资源路径。
  2. 转发是一次请求,而重定向是两次请求。所以一般可以说重定向是 2 次转发。
  3. 转发只能在自己内部服务器资源内相互转发(同一项目内),而重定向可以访问其他站点。
  4. 推荐使用请求转发,因为请求转发耗的网络资源相对比重定向少。(因为请求转发是服务器内部行为)
posted @ 2022-10-26 19:56  软柠柠吖  阅读(32)  评论(0编辑  收藏  举报