概述

最近项目组后端需要一个简单的web后台,于是用Ant Design Vue撸了一个页面,嫌麻烦也就没有前后端分离了。骚操作大致归纳如下:

  • Vue 打包后得到 dist
  • 将 dist 下生成的静态文件拷贝到 SpringBoot 的 resources/static 目录下

但是过程中遇到几个问题,既然踩过坑那么久将其记录下来,防止有和我一样的同学们重复踩坑。

Vue的两种路由模式

对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-router 存在的意义。前端路由的核心,就在于改变视图的同时不会向后端发出请求。

hash模式

哈希模式,即地址栏URL中的#符号(此hsah 不是密码学里的散列运算)。

比如这个URL:http://www.abc.com/#/hello, hash 的值为#/hello。它的特点在于:hash 虽然出现 URL 中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

hash模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.abc.com, 因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误;

history模式

history模式,利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。(需要特定浏览器支持)

history模式下,前端的url必须和实际向后端发起请求的url 一致,如http://www.abc.com/book/id 。如果后端缺少对/book/id 的路由处理,将返回404错误。

这两个方法应用于浏览器的历史记录站,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改是,虽然改变了当前的 URL,但你浏览器不会立即向后端发送请求。

问题

一开始使用的是 history 模式,但是打包到 SpringBoot 项目运行后发现刷新页面会有404错误,因为刷新页面向后端发请求,后端没有对应的接口所以报 404。

因此转用 hash模式。虽然解决了刷新不会向后端发请求的问题,但是还有一个尴尬的问题。缓存问题,即前端更新重新打包部署到 tomcat 后,不会显示最新的页面,需要浏览器清除缓存后才能看到最新的页面。

最终解决办法

前端路由模式采用 history 模式,后端针对 404 问题做特殊处理。最终一并解决刷新 404 问题和缓存问题。

后端解决 404 的代码如下所示,将该代码放到 SpringBoot 的启动引导类中即可。其中 /index.html 对应你 Vue 项目的首页。

/**
 * 支持前端路由的 history 模式
 * @return
 */
@Bean
public WebServerFactoryCustomizer webServerFactoryCustomizer() {

    return new WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>() {
        @Override
        public void customize(ConfigurableServletWebServerFactory factory) {

            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");
            factory.addErrorPages(error404Page);
        }
    };
}

有些小伙伴们可能搜索到的版本是这样的:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {

    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {

            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");

            container.addErrorPages(error404Page);
        }
    };
}

最终发现 EmbeddedServletContainerCustomizer找不到,无法引入。那是因为 EmbeddedServletContainerCustomizer 是SpringBoot1.X 的类,SpringBoot2.X 可以用 WebServerFactoryCustomizer

关于我

微信公众号:Guevara的笔记,技术菜鸟记录技术学习过程

微信公众号:Guevara的笔记

Logo

前往低代码交流专区

更多推荐