Spring Boot+Vue先后端分离,如何避免前端页面 404

问题倒不难,可是这个问题以前被松哥忽略了。前两天有小伙伴提出这个疑问,我以为有必要写篇文章和你们捋一捋这个问题。前端

先来看一个简短的视频:vue

视频地址java

一个简单的配置就解决掉 404 问题了,接下来,我再来把这件事的前因后果和你们仔细捋一捋。vue-router

1.职责划分

在传统的先后端不分的开发中,权限管理主要经过过滤器或者拦截器来进行(权限管理框架自己也是经过过滤器链来实现功能),若是用户不具有某一个角色或者某一个权限,则没法访问某一个页面。后端

可是在先后端分离中,页面的跳转通通交给前端去作,后端只提供数据,这种时候,权限管理不能再按照以前的思路来。浏览器

首先要明确一点,前端是展现给用户看的,全部的菜单显示或者隐藏目的不是为了实现权限管理,而是为了给用户一个良好的体验(把用户没有权限的按钮隐藏起来,避免用户点击后提示 403,提升用户体验),不能依靠前端隐藏控件来实现权限管理,即数据安全不能依靠前端。安全

这就像普通的表单提交同样,前端作数据校验是为了提升效率,提升用户体验,后端才是真正的确保数据完整性。session

因此,真正的数据安全管理是在后端实现的,后端在接口设计的过程当中,就要确保每个接口都是在知足某种权限的基础上才能访问,也就是说,不怕将后端数据接口地址暴露出来,即便暴露出来,只要你没有相应的角色/权限,也是访问不了的。框架

前端为了良好的用户体验,须要将用户不能访问的接口或者菜单隐藏起来。页面的跳转,按钮的隐藏/展现等等,通通在前端来实现。前后端分离

2.存在的问题

当先后端分离以后,对于前端所承担的职责,你们可能会面临一个问题:若是用户直接在地址拦输入某一个页面的路径,怎么办?

此时,若是没有作任何额外的处理的话,用户确实能够经过直接输入某一个路径进入到系统中的某一个页面中,可是,不用担忧数据泄露问题,由于没有相关的角色/权限,就没法访问相关的接口,即便进入到相关的页面,也看不到数据。

可是,若是用户非这样操做,进入到一个空白的页面,用户体验很差,冒出来一个空白页面,有的用户就手足无措了。

此时,咱们可使用 Vue 中的前置路由导航守卫,来监听页面跳转,若是用户想要去一个未获受权的页面,则直接在前置路由导航守卫中将之拦截下来,重定向到登陆页,或者直接就停留在当前页,不让用户跳转,也能够顺手再给用户一点点未获受权的提示信息。

以 vhr 中的代码为例,我在 main.js 中定义了前置路由导航守卫:

router.beforeEach((to, from, next) => {
    if (to.path == '/') {
        next();
    }else {
        if (window.sessionStorage.getItem("user")) {
            initMenu(router, store);
            next();
        }else{
            next('/?redirect='+to.path);
        }
    }
})

这个方法有点相似于 Java 中的过滤器,to 表示要去哪里,有点像 HttpServletResponse;from 表示从哪来,有点像 HttpServletRequest;next 表示一个请求继续向下执行的方法,有点相似于 FilterChain。

这里会监控到全部的页面路由/跳转,主要逻辑是这样:

  1. 若是要去的地址是 ‘/’,即要去的地方是登陆页面,则直接执行 next 方法表示放行。
  2. 若是要去的地址不是 ‘/’,那就要看用户是否登陆了,若是已经登陆了,则先初始化菜单,而后调用 next 方法继续向下走,想去哪去哪。
  3. 若是没有登陆,则调用 next 方法,跳转路径是 ‘/’,即回到登陆页面,同时携带上一个 redirect 参数,这个是重定向的地址,这个参数的做用是这样:例如我原本输入 ‘/aa/bb’,结果由于没有登陆,自动跳转到项目登陆页面,当我登陆成功后,自动跳回 ‘/aa/bb’。

有这个配置以后,就不怕用户乱跳转了,若是没有登陆随意输入一个地址,就会回到登陆页面。

3. 404问题

上面的配置还存在一个 404 问题。

在用户尚未登陆的时候,若是他在浏览器输入一个不存在的地址,就会自动回到登陆页面,这没有问题,可是用户若是已经登陆了,在浏览器输入一个不存在的地址,这个时候就会发生 404,当你没作任何定义的时候,所谓的 404 页面其实就是一片空白。

要解决这个问题,不少小伙伴第一个思路就是能不能在前置路由导航守卫里边作一个判断,当你要跳转的时候,先去判断一个跳转的路径是否存在,若是存在再去跳转,不然就不去跳转。

3.1 动态路由

这个思路看起来没问题,但实际上还有更简便的办法,那就是使用 vue-router 中的动态路由。

举一个简单的例子,咱们有一个用户展现的页面,这个页面会根据不一样的用户 id 来展现不一样的用户数据,因此咱们在 router.js 中能够按以下方式来定义路由:

routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]

注意这里标记的参数 id 前面有一个 : 。定义完成后,之后像 /user/1/user/2 都会映射到相同的路由。而像地中的 1 、2 等参数,咱们则能够经过 this.$route.params.id 获取。

上面这种是设置一个参数,咱们也能够设置多个参数,咱们能够参考官方给出的一个表格:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9CBWcZv3-1584424148156)(http://img.itboyhub.com/2020/03/vue-router-1.png)]

若是有多个参数,也能够经过 this.$route.params 来获取参数的值。

注意,在动态路由匹配时,若是咱们从 /user/1 切换到 /user/2 ,原有的 User 组件是不会销毁的,这也意味着组件的生命周期钩子函数不会再被调用,那么要怎么刷新数据呢?这个时候咱们能够采用 beforeRouteUpdate 导航守卫,在导航守卫中完成数据更新:

router.beforeRouteUpdate((to, from, next) => {
    //刷新数据
})

3.2 解决 404

最后,就是咱们本文要说的 404 问题了。看懂了前面,如何解决 404 其实就很容易明白了。

咱们可使用通配符 * 来匹配任意路径,例以下面这段匹配格式:

{
  // 会匹配全部路径
  path: '*'
}

这个匹配规则会匹配到全部路径,一般就是用来解决前端页面的 404 问题。也能够本身定义一些前缀,例以下面这样:

{
  // 会匹配以 `/javaboy-` 开头的任意路径
  path: '/javaboy-*'
}

当咱们使用通配符的时候,能够经过 this.$route.params.pathMatch 来获取通配符匹配到的路径,例如用户请求路径是 /javaboy-aaa,则 this.$route.params.pathMatch 的值就为 aaa

另外还有一个比较重要的点,就是通配符路径的顺序问题。若是路径带有通配符,通常来讲要放在路由的最后面。