21.5.3 视图重定向

    有时,我们想要在视图渲染之前,先把一个HTTP重定向请求发送回客户端。比如,当一个控制器成功地接受到了POST过来的数据,而响应仅仅是委托另一个控制器来处理(比如一次成功的表单提交)时,我们希望发生一次重定向。在这种场景下,如果只是简单地使用内部转发,那么意味着下一个控制器也能看到这次POST请求携带的数据,这可能导致一些潜在的问题,比如可能会与其他期望的数据混淆,等。此外,另一种在渲染视图前对请求进行重定向的需求是,防止用户多次提交表单的数据。此时若使用重定向,则浏览器会先发送第一个POST请求;请求被处理后浏览器会收到一个重定向响应,然后浏览器直接被重定向到一个不同的URL,最后浏览器会使用重定向响应中携带的URL发起一次GET请求。因此,从浏览器的角度看,当前所见的页面并不是POST请求的结果,而是一次GET请求的结果。这就防止了用户因刷新等原因意外地提交了多次同样的数据。此时刷新会重新GET一次结果页,而不是把同样的POST数据再发送一遍。

    强制重定向的一种方法是,在控制器中创建并返回一个Spring重定向视图RedirectView的实例。它会使得DispatcherServlet放弃使用一般的视图解析机制,因为你已经返回一个(重定向)视图给DispatcherServlet了,所以它会构造一个视图来满足渲染的需求。紧接着RedirectView会调用方法,发送一个HTTP重定向响应给客户端浏览器。

    如果你决定返回RedirectView,并且这个视图实例是由控制器内部创建出来的,那我们更推荐在外部配置重定向URL然后注入到控制器中来,而不是写在控制器里面。这样它就可以与视图名一起在配置文件中配置。关于如何实现这个解耦,请参考 重定向前缀——redirect:一小节。

    RequestMappingHandlerAdapter提供了一个"ignoreDefaultModelOnRedirect"标志。它被用来标记默认Model中的属性永远不应该被用于控制器方法的重定向中。控制器方法应该声明一个RedirectAttributes类的参数。如果不声明,那就没有参数被传递到重定向的视图RedirectView中。在MVC命名空间或MVC Java编程配置方式中,为了维持向后的兼容性,这个标志都仍被保持为false。但如果你的应用是一个新的项目,那么我们推荐把它的值设置成true

    请注意,当前请求URI中的模板变量会在填充重定向URL的时候自动对应用可见,而不需要显式地在ModelRedirectAttributes中再添加属性。请看下面的例子:

    另外一种向重定向目标传递数据的方法是通过 闪存属性(Flash Attributes)。与其他重定向属性不同,flash属性是存储在HTTP session中的(因此不会出现在URL中)。更多内容,请参考 一节。

    一个特别的视图名前缀能完成这个解耦:redirect:。如果返回的视图名中含有redirect:前缀,那么UrlBasedViewResolver(及它的所有子类)就会接受到这个信号,意识到这里需要发生重定向。然后视图名剩下的部分会被解析成重定向URL。

    这种方式与通过控制器返回一个重定向视图RedirectView所达到的效果是一样的,不过这样一来控制器就可以只专注于处理并返回逻辑视图名了。如果逻辑视图名是这样的形式:redirect:/myapp/some/resource,他们重定向路径将以Servlet上下文作为相对路径进行查找,而逻辑视图名如果是这样的形式:redirect//myhost.com/some/arbitrary/path,那么重定向URL使用的就是绝对路径。

    注意的是,如果控制器方法注解了@ResponseStatus,那么注解设置的状态码值会覆盖RedirectView设置的响应状态码值。

    redirect:前缀一样,如果控制器中的视图名使用了前缀,控制器本身并不会发觉任何异常,它关注的仍然只是如何处理响应的问题。