Vue-router的实现原理、hash和history两种模式的区别、history模式部署后刷新报404

一、Vue-router的实现原理是什么?

Vue-router是Vue.js官方提供的路由管理库,可以在Vue.js应用程序中实现客户端路由。

Vue-router的实现原理可以简单概括为以下几个步骤:

  1. 定义路由规则:在Vue.js应用程序中定义路由规则,即指定哪些URL路径应该由哪些组件渲染。
  2. 创建路由实例:使用VueRouter类创建一个路由实例,将路由规则作为参数传递给该实例。
  3. 将路由实例挂载到Vue实例上:在Vue.js应用程序中将路由实例挂载到Vue实例上,使得所有的组件都可以访问路由实例。
  4. 监听URL变化:当URL发生变化时,路由实例会根据定义的路由规则匹配相应的组件,并将组件渲染到应用程序的页面上。
  5. 实现导航:Vue-router提供了一些API,可以通过编程方式实现导航,例如:push()、replace()、go()、back()等方法。

在实现路由的过程中,Vue-router利用了Vue.js的组件系统,将路由组件定义为Vue组件,实现了路由和组件的无缝衔接。同时,Vue-router还利用了浏览器的History API实现了前端路由的实现。

总的来说,Vue-router的实现原理是通过监听URL的变化,根据定义的路由规则匹配相应的组件,并将组件渲染到应用程序的页面上,实现了前端路由的实现。

二、出现的问题

项目本地运行时候,首页页面刷新均无问题。部署到服务器之后,刷新页面报错、出现404。

vue项目的vue-router的mode为history路由模式时,若后端未进行相应的配置,可能会发生这种情况。

前端路由,即由前端来维护一个路由规则。实现有两种,一种时利用url的hash,也就是常说的锚点(#),JS通过hashChange事件来监听url的改变,IE7及以下需要轮询;另一种是HTML5的History模式,它使url看起来像普通网站那样,以“/”分割,没有#,但页面并没有跳转,不过使用这种模式需要服务端的支持,服务端在接受到所有请求后,都指向index.html文件,或设置404页面为index.html。不然刷新时页面会出现404。

三、路由的工作模式:

  1、hash模式(默认)

        使用URL的hash来模拟一个完整的URL,当URL发生改变时,页面不会重新加载,其显示的网络路径中会有#号,这是最安全的模式,因为他兼容所有的浏览器和服务器 

  • 地址中永远带着#号,不美观
  • 若以后将地址通过第三方手机app分享,若app校验严格,地址会被标记为不合法
  • 兼容性较好

  2、history模式

        美化后的hash模式,路径中会去掉#。依赖于html5的history,pushState API,所以要担心IE9及以下的版本。并且还包括back、forward、go三个方法,对应浏览器的前进、后退、跳转操作,就是浏览器左上角的前进后退等按钮进行的操作 

  • 地址干净,美观
  • 兼容性和hash模式相比略差
  • 应用部署上线时需要后端人员支持,解决页面服务器端刷新404的问题

   3、abstract (不常用)

        适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式

hash和history两种模式的区别:

1、hash 就是指 url 尾巴后的 # 号以及后面的字符,history没有底带#,外观上比hash 模式好看些

2、原理的区别(原理)

        hash原理:hash通过监听浏览器的onhashchange()事件监听URL变化,查找对应的路由规则匹配相应的组件,在不刷新页面的情况下跳转路由。
        history原理: 利用H5的 history中新增的两个API history.pushState() 或 history.replaceState() 修改URL,通过onpopstate监听URL变化,渲染对应的组件。

pushstate和replacestate事件是HTML5中的两个重要事件,用于在浏览器历史记录中添加或修改记录,而不需要重新加载页面。
pushstate事件可以将一个新的历史记录添加到浏览器历史记录中,同时改变当前页面的URL,但不会刷新页面。这个事件通常用于实现单页应用程序的导航。
replacestate事件与pushstate事件类似,但是它会替换当前的历史记录,而不是添加一个新的记录。这个事件通常用于在不刷新页面的情况下修改URL。
这两个事件都可以通过JavaScript的history对象来触发,并且可以传递一个状态对象作为参数,这个状态对象可以在后续的popstate事件中被访问到。 

3、hash 能兼容到IE8, history 只能兼容到 IE10

4、hash ——由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发 hashchange 事件(hashchange只能改变 # 后面的url片段);虽然hash路径出现在URL中,但是不会出现在HTTP请求中,对后端完全没有影响,因此改变hash值不会重新加载页面,基本都是使用 hash 来实现前端路由的。

5、history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。还有最重要一点是history路由害怕刷新,因为切换路由后浏览器中url改变,再刷新的话会重新向服务器发送请求,所以后端需要做简单的配置。

另外,根据 Mozilla Develop Network 的介绍,调用 history.pushState() 相比于直接修改 hash,存在以下优势:

  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
  • pushState() 可额外设置 title 属性供后续使用。

当然啦,history 也不是样样都好。SPA 虽然在浏览器里游刃有余,但真要通过 URL 向后端发起 HTTP 请求时,两者的差异就来了。尤其在用户手动输入 URL 后回车,或者刷新(重启)浏览器的时候。

个人在接入微信的一个活动开发过程中 开始使用的hash模式,但是后面后端无法获取到我#后面的url参数,于是就把参数写在#前面,但是讨论后还是决定去掉这个巨丑的#
于是乎改用history模式,但是开始跑流程的时候是没问题,但是后来发现跳转后刷新或者回跳,会报一个404的错误,找不到指定的路由,最后后端去指向正确的路由 加了/hd/xxx 去匹配是否有这个/hd/{:path} 才得以解决

总结

  • 1 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
  • 2 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
  • 3 结合自身例子,对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 history 模式即可,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持。

四、出现问题:history模式一刷新就报错404

解决办法

解决办法一:

文档里有说到history模式下如果后端,前端不做任何处理,刷新页面就会报404.
后端配置请看官方文档,这里只介绍一下前端需要配置的地方

第一步:如何切换history模式 在router.js中配置

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
  // 切换路由后滚动条置顶
  scrollBehavior() {
    return {
      x: 0,
      y: 0
    }
  }
})

export default router

第二步在vue.config.js中加上如下配置

module.exports = {
    publicPath: '/',   //这个必须,引入静态资源需要从根路径引入,否则会找不到静态资源
    devServer: {
        // history模式下的url会请求到服务器端,但是服务器端并没有这一个资源文件,就会返回404,所以需要配置这一项
        historyApiFallback: {
            index: '/index.html' //与output的publicPath
        },
      },
}

解决办法二:

应用部署上线时需要后端人员支持,解决页面服务器端刷新404的问题

第一步:安装插件

npm install --save connect-history-api-fallback

第二步: node后端配置

var history = require('connect-history-api-fallback');
const express = require('express');
const history = require('connect-history-api-fallback');
const app = express();
app.use(history())
app.use(express.static(__dirname + '/static'))
app.get('/person', (req, res) => {
    res.send({
        name: 'zhang',
        age: 20
    })
})
app.listen(5000, (err) => {
    if (!err) console.log('服务器启动了');
})


  • 7
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值