前言

vue 项目中,我们比较常用的模式为 hash 和 history 模式 默认情况下,vue 项目采用的就是 hash 模式 有些人对 history 模式下,为什么需要服务器做相应配置,以及如何配置不甚理解,所以这篇文章就对此做出分析,重点是让大家理解,为什么 history 模式下需要服务器做配置 这里会对 hash 模式和 history 模式都做出说明,通过对比,才能更好的理解我们的行为

1. hash 模式

1.1 什么是 hash 模式

先从一个熟悉的锚标记案例开始,帮助大家理解 hash 模式是怎么回事

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        ul {
            list-style-type: none;
        }

        li {
            line-height: 30px;
        }

        div {
            height: 800px;
        }
    </style>
</head>

<body>
    <ul>
        <li><a href="#lish">历史沿革</a></li>
        <li><a href="#mingren">名人典故</a></li>
        <li><a href="#jinri">今日发展</a></li>
        <li><a href="#weilai">未来规划</a></li>
    </ul>

    <div id="lish">
        <h3>历史沿革</h3>
        历史沿革历史沿革历史沿革历史沿革历史沿革历史沿革历史沿革历史沿革
    </div>
    <div id="mingren">
        <h3>名人典故</h3>
        名人典故名人典故名人典故名人典故名人典故
    </div>
    <div id="jinri">
        <h3>今日发展</h3>
        今日发展今日发展今日发展今日发展今日发展今日发展
    </div>
    <div id="weilai">
        <h3>未来规划</h3>
        未来规划未来规划未来规划未来规划未来规划未来规划未来规划未来规划
    </div>
</body>

</html>

运行效果如下图

GIF 2022-4-27 18-53-52.gif

总结:

  • 点击链接时,没有跳转到其他页面
  • 点击连接时,在当前页面内进行跳转
  • 点击连接时,地址栏中 # 后面的部分发生变化

这个 # 后面的部分就叫做 hash

http://127.0.0.1:5500/hash.html#weilai

如下面的代码

<a href="#lish">历史沿革</a>

当超链接的 href 值不是某个页面,而是使用 hash 值时,是不会发生页面跳转的,这点很重要

vue-router 就是利用了这个特点,实现了地址栏的 hash 值发生变化后,切换不同的组件进行渲染

1.2 hash 模式特点

  • 在浏览器支持度上面,Hash 模式是比较强势的,甚至能兼容低版本的 IE 浏览器
  • 唯一的缺点就是长得丑

2. history 模式

HTML5 History API 提供了一个 history.pushState 和 history.replaceState 方法(浏览器支持情况不是很乐观),它能让开发人员在不刷新网页的情况下改变站点的 URL

我们这里不去详细解释HTML5 History API

通过如下配置,就可以开启 vue-router 的 history 模式

const router = new VueRouter({
  routes,
  mode: 'history',
})

地址栏中的地址如下

http://localhost:8081/food

没有了 hash ,长得确实顺眼多了

3. history 模式的问题

下面使用到的地址栏中,再域名+端口后面都会出现一个 douyin路径,这是因为我们是在上一篇《一个域名部署多个vue项目》基础上实现的,大家看完上一篇,就理解了。自己练习的话,直接忽略这个路径即可

history 模式很好,长得很漂亮,但是漂亮的人一般都不好养

在生产环境中,history 模式有一个比较大的问题,就是当手动刷新时,会报404错误

我们来演示一遍,看下面的动图

我们复盘一下刚才的操作

① 地址栏中输入http://localhost:8080/douyin/,页面正常显示,上方导航可以看到,但是没有具体内容,因为路由规则中没有匹配 “/”

② 依次点击几个导航,都可以正常切换,点击播放进入到详情页也没有问题

③ 当地址栏中地址变成 http://localhost:8080/douyin/knowledge 时(knowledge也可以换成quadratic、food),此时手动刷新页面(在地址栏中敲击回车或者F5刷新),页面最后就报404了

image.png

④ 如果路由模式为 hash 模式,就不会出现上面的问题,大家可以自己尝试

5. 寻找原因

无论是 hash 模式,还是 history 模式,浏览器中输入如下地址

http://localhost:8081/douyin

浏览器一定会像服务端发送一个请求

image.png

我们也知道,默认请求的一定是目录下的 index.html(这个是很多服务器的默认设置)

而 index.html 中引用了 js、css 等文件,所以我们看下面又请求了其他一些资源

所以,我们可以看到这样的页面

image.png

当我们点击页面中的导航时

  • 如果是 hash 模式,当地址栏中的 hash 发生改变时,浏览器不会向服务端发送请求,所以会匹配路由规则,进而进行组件切换
  • 如果是 history 模式,点击导航,地址栏发生变化后,会利用 h5 的 history API进行导航,浏览器也不会向服务器发送请求

但是,当我们浏览到某个地址下时,如 http://localhost:8080/douyin/knowledge(在 hash 模式下,地址为 http://localhost:8080/douyin/#/knowledge),在地址栏中敲击回车,或者刷新页面时,两者的行为就不一样了

1、hash 模式

hash 模式下下,只将 hash 前面的部分当作地址,所以会向服务端重新请求 http://localhost:8080/douyin/,服务端仍然会返回 index.html,此文件再下载引入的 js、css 等文件,然后根据地址栏中的 hash 值匹配路由,所以刷新之后,与刷新之前的页面内容是一致的(因为 hash 值没有变化)

image.png

2、history 模式

history 模式下,会将地址栏中的地址全部看作请求地址,所以刷新后,会向服务端请求这个地址

image.png

而我们的前端项目下,只有一个 index.html 和一些 js、css、图片等文件,根本没有请求的资源,所以服务器就返回 404了

我这里使用的是 http-server 这个简单的服务器,其他服务器的行为基本一致,如 nginx 返回的 404 如下所示

image.png

总结:现在我们找到了 history 模式下出现404的原因,也理解了 hash 模式和 history 模式之间的区别

5. 解决方案

问题既然找到了,解决起来自然就有思路了

为了更加贴近实际,我们这次的服务器使用 nginx

首先将 douyin 项目拷贝到 nginx 的根目录下,然后打开 nginx 的配置文件(这里选择的是Nginx1.15.11\conf\vhosts\0localhost_80.conf),添加如下一行配置

image.png

try_files $uri $uri/ /admin/index.html;

上面代码的作用是,配置url重写语句,注意是重写,不是重定向

不改变url的情况重写浏览器内容,重写到index.html,因为这个index.html使我们项目的入口,index.html里面会读取当时打包好的app.js,就可以读取到路由配置,以实现我们浏览器的url对应的路由页面

重启 nginx,然后随意刷新浏览器,再也不会出现404 问题了

image.png

如图上注释所说:

① 浏览器请求 http://localhost/douyin/knowledge nginx 发现没有资源,所以返回404

② nginx 紧接着又将 index.html 返回,浏览器加载后,又去加载其中引用的 js、css 等文件,然后路由规则根据地址栏中的地址,去匹配对应的组件进行渲染

6. 路由模式总结

hash 模式除了长得丑点外,优点还是很多的,比如不需要服务器配置,兼容性好等,所以像 网易云音乐等都在使用

history 颜值出众,但是服务器需要做些配置,但是也不复杂

这里的服务器与前后端分离开发中的服务器端不是一个概念,那个指的是 java、php 等后端服务

这里的服务器指的是前端项目部署的服务器,如 nginx、apache等,所以需要在这些服务器的配置文件中做配置

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐