文章目录
1. 请求转发与重定向的定义
-
请求转发(Forward):请求转发是服务器行为,它只产生一次请求,客户端请求到达服务器之后中会发生一次转发,之后服务器才将结果发送到客户端。
-
请求重定向(Redirect):重定向是客户端(浏览器)行为,它会产生两次请求,每次都是从客户端发起。当客户端发送
request1
给第一个服务器端时,第一个服务器端返回一个response1
给客户端,紧接着客户端(浏览器)继续发送request2
给第二个服务器端,第二个服务器端返回一个response2
给客户端。
2. 请求转发与重定向的区别
2.1 请求方式
-
请求转发(Forward):发生在服务端程序内部,当服务器端收到一个客户端的请求之后,会先将请求,转发给目标地址,再将目标地址返回的结果转发给客户端(浏览器)。
-
请求重定向(Redirect):发生在客户端与多个服务端之间,服务器端接收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头中记录了,客户端需要再次发送请求(重定向)的 URL 地址。客户端再收到了地址之后,将发送一个新的请求给该URL 地址。
-
注意事项:
- 重定向时不管第一次请求时的方式是什么,第二次请求时方式都是GET;而转发时,两次的方式是一样的。
2.2 数据共享
-
请求转发是服务器端实现的,所以整个执行流程中,客户端(浏览器端)只需要发送一次请求,因此整个交互过程中使用的都是同一个 Request 请求对象和一个 Response 响应对象,所以整个请求过程中,请求和返回的数据是共享的。
-
而请求重定向客户端发送两次完全不同的请求,所以两次请求中的数据是不同的,要想传内容或者参数只能在url路径后面添加参数例如:url地址?参数名称=参数值;response.sendRedirect(“url地址?参数名称=参数值”)
2.3 资源访问
-
请求转发(Forward):
- 请求转发是服务器内部调用的地址请求,因此请求转发的路径必须是同一个Web容器下的URL,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。因为转发行为是浏览器只做了一次访问请求,在客户浏览器路径栏显示的仍然是其第一次访问的路径(转发不会改变url路径),也就是说客户是感觉不到服务器做了转发的。
- 转发可以访问WEB-INF下资源,重定向不能直接访问WEB-INF下资源。
- WEB-INF属于服务器私有目录【服务器内部可以访问,浏览器不能直接访问】。
- 在过滤器中,如果使用转发后,则不会进入过滤器中。因为转发是一次请求,进入服务器后,已经经过了过滤器。当进行转发后,没有重新发请求,则不会再进入到过滤器中。如果是重定向,则是重客户端重新发的请求,则还是会进入过滤器,再访问目标资源。
-
请求重定向(Redirect):
- 重定向是对浏览器的请求直接做出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求。重定向行为是浏览器做了至少两次的访问请求的,在客户浏览器路径栏显示的是其重定向的路径(url路径会改变),因此重定向可以访问服务器外的资源,客户也可以观察到地址的变化的。
3. 请求转发和重定向的选择
- 页面变更:重定向后,url路径会改变;转发不会改变url路径,还是原先的访问路径,在应用中往往增删改使用重定向。比如我们在使用完增删改后,如果路径不改变,则继续刷新,会出现增删改异常;而查询需要使用转发,转发后,可实时变更使用request传值。
- 内部资源访问:
- 在同一Web应用程序的两个请求间传递数据时,在转发与重定向之间,只能通过转发实现。
- 对内部安全页面跳转则必须使用转发,例如转发到内部[WEB-INF]下的安全页面,则必须使用转发,使用重定向则访问不了。
- 外部资源访问:如果需要跳转到其它服务器上的资源,则必须使用重定向,比如访问百度。
- 如果既想要实现路径跳转,又需要实现数据共享,使用请求转发!如果只是纯粹的想要实现路径跳转,我们可以使用重定向,但是优先选择请求转发,因为转发效率更高。
4. SpringMVC请求转发和重定向
- 转发路径规则:如果传递给
HttpServletResponse.sendRedirect
方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher
对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。
4.1 请求转发
-
特点:请求转发地址栏不会发生改变、只发送一次请求、能携带原有的参数,但只可以在同一个服务器中进行转发。
-
文件夹目录结构如下:
-
传统的请求转发:
- 控制器中的代码:
// 传统的请求转发 @RequestMapping("/fun1") public void fun1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("hobby","fun1"); request.getRequestDispatcher("/WEB-INF/manager/teacher.jsp").forward(request,response); System.out.println("fun1"); }
- 在webapp目录下的:WEB-INF/manager/teacher.jsp中的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>这是老师页面</title> </head> <body> 老师喜欢:<%= request.getAttribute("hobby")%> </body> </html>
-
访问localhost:80/fun1,页面效果:
-
SpringMVC中不经过视图解析器的请求转发:
// SpringMVC中不经过视图解析器的请求转发(不携带数据) @RequestMapping("/fun2") public String fun2() { System.out.println("fun2"); return "forward:/WEB-INF/worker/doctor.jsp"; } // SpringMVC中不经过视图解析器的请求转发(携带数据) @RequestMapping("/fun3") public ModelAndView fun3(ModelAndView modelAndView) { modelAndView.addObject("hobby","fun3"); modelAndView.setViewName("forward:/WEB-INF/worker/doctor.jsp"); System.out.println("fun3"); return modelAndView; }
-
SpringMVC中经过视图解析器的请求转发:
// SpringMVC中经过视图解析器的请求转发(不携带数据) @RequestMapping("/fun4") public String fun4() { System.out.println("fun4"); return "/WEB-INF/worker/doctor.jsp"; } // SpringMVC中经过视图解析器的请求转发(携带数据) @RequestMapping("/fun5") public ModelAndView fun5(ModelAndView modelAndView) { modelAndView.addObject("hobby","fun5"); modelAndView.setViewName("/WEB-INF/worker/doctor.jsp"); System.out.println("fun5"); return modelAndView; }
-
SpringMVC在控制器之间转发,并共享数据:
@RequestMapping("/test1") public ModelAndView test1(ModelAndView modelAndView) { System.out.println("test1"); modelAndView.addObject("hobby","football"); modelAndView.setViewName("/test2"); return modelAndView; } @RequestMapping("/test2") public ModelAndView test2(ModelAndView modelAndView, HttpServletRequest request) { System.out.println("test2"); modelAndView.setViewName("/WEB-INF/manager/teacher.jsp"); Object hobby = request.getAttribute("hobby"); System.out.println(hobby); return modelAndView; } /*控制台结果如下 test1 test2 football */
- 访问localhost:80/test1,页面效果:
- 访问localhost:80/test1,页面效果:
4.2 重定向
-
传统的重定向:
@RequestMapping("/test3") public void fun1(HttpServletRequest request, HttpServletResponse response) throws IOException { response.sendRedirect("/index.jsp"); }
-
SpringMVC中不带参数的重定向:重定向不能访问WEB-INF下的资源
@RequestMapping(value = "/test4") public String test4() { return "redirect:/test.jsp"; // return "redirect:/WEB-INF/student.jsp"; } @RequestMapping(value = "/test5") public ModelAndView test5() { ModelAndView mv = new ModelAndView(); mv.setViewName("redirect:/index.jsp"); // mv.setViewName("redirect:/WEB-INF/student.jsp"); return mv; }
-
SpringMVC中带参数的重定向:
-
redirectAttributes.addAttributie(“prama”,value); 这种方法相当于在重定向链接地址上追加传递的参数。上面示例相当于请求 http://localhost:8080/test.jsp?param=1。
@RequestMapping("/test6") private String test6(RedirectAttributes redirectAttributes ) { redirectAttributes.addAttribute("param", 1); return "redirect:/test.jsp"; }
-
redirectAttributes.addFlashAttributie(“prama”,value); 方法是隐藏了参数,链接地址上不直接暴露,用(@ModelAttribute(value = “prama”)String prama)的方式获取参数。
@RequestMapping("/test7") private String test7(RedirectAttributes redirectAttributes ) { redirectAttributes .addFlashAttribute("param", 1001); return "redirect:/test8"; } // 接收参数 @RequestMapping("/test8") @ResponseBody private String test8(@ModelAttribute("param") String param) { System.out.println(param); // 输出1001 return "hello"; }
-
参考博客: