美文网首页
SpringMVC 如何优雅地进行 301 跳转

SpringMVC 如何优雅地进行 301 跳转

作者: Boreasy | 来源:发表于2017-11-21 16:51 被阅读0次

    对 SpringMVC 有一定了解的同学对「redirect」和「forward」的语法都不陌生。

    @GetMapping("/product/{id}")
    public String forward(@PathVariable("id") String id) {
        return "forward:/product2/{id}";
    }
    
    @GetMapping("/hello")
    public String redirect() {
        return "redirect:/world";
    }
    
    @GetMapping("/somepage")
    public String toPage() {
        return "templates/hello";
    }
    

    如上面的例子,请求/somepage会访问我们指定的页面,也是最常见的用法之一。而请求/product/111 将 forward 到 /product2/111,请求 /hello 将 redirect 到 /world。这两种用法由 SpringMVC 提供,可以满足大部分的重定向需求。

    但实际项目中,往往需要考虑 SEO 的因素。SpringMVC 提供的 redirect 机制实际上是 302 跳转,302 跳转代表的是一种临时的状态。实际开发过程中,我们往往需要通知搜索引擎页面 A 已经永久的替换为 页面 B 了,以便搜索引擎将旧页面权重传递到新页面。此时应该使用 301 跳转。

    SpringMVC 没有提供 301 跳转,那么我们应该怎么实现呢?最直观的办法显然是

    public void redirect301(HttpServletResponse response) {
        response.setStatus(301);
        response.setHeader("Location", "xxx");
    }
    

    相比原生提供的重定向机制,这种实现显然不够优雅。既然如此,我们何不借鉴下 SpringMVC 的实现呢?

    全局搜索「redirect:」、「forward:」,很容易找到他的实现org.springframework.web.servlet.view.UrlBasedViewResolver.createView

    protected View createView(String viewName, Locale locale) throws Exception {
        // If this resolver is not supposed to handle the given view,
        // return null to pass on to the next resolver in the chain.
        if (!canHandle(viewName, locale)) {
            return null;
        }
        // Check for special "redirect:" prefix.
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
            view.setHosts(getRedirectHosts());
            return applyLifecycleMethods(viewName, view);
        }
        // Check for special "forward:" prefix.
        if (viewName.startsWith(FORWARD_URL_PREFIX)) {
            String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
            return new InternalResourceView(forwardUrl);
        }
        // Else fall back to superclass implementation: calling loadView.
        return super.createView(viewName, locale);
    }
    

    处理逻辑一目了然,我们的解决方案也呼之欲出了:继承 UrlBasedViewResolver 并重写 createView 方法,处理我们自定义的前缀。

    private static final String REDIRECT_301_URL_PREFIX = "redirect 301:";
    
    @Override
    protected View createView(String viewName, Locale locale) throws Exception {
        if (!canHandle(viewName, locale)) {
            return null;
        }
        if (viewName.startsWith(REDIRECT_301_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_301_URL_PREFIX.length());
           RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible(), false);
            view.setStatusCode(HttpStatus.MOVED_PERMANENTLY);
            return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
        }
        return super.createView(viewName, locale);
    }
    

    配置完成以后就可以优雅的进行 301 跳转了。

    @GetMapping("/hello")
    public String redirect301() {
        return "redirect 301:/world";
    }
    

    相关文章

      网友评论

          本文标题:SpringMVC 如何优雅地进行 301 跳转

          本文链接:https://www.haomeiwen.com/subject/sfjwvxtx.html