Hash模式与History模式

13.1 Hash模式与History模式区别
前端路由中,不管是什么实现模式,都是客户端的一种实现方式,也就是当路径发生变化的时候,是不会向服务器发送请求的。

如果需要向服务器发送请求,需要用到ajax方式。

两种模式的区别

首先是表现形式的区别

Hash模式

https://www.baidu.com/#/showlist?id=22256
1
hash模式中路径带有#, #后面的内容作为路由地址。可以通过问号携带参数。

当然这种模式相对来说比较丑,路径中带有与数据无关的符号,例如#与?

History模式

https://www.baidu.com/showlist/22256
1
History模式是一个正常的路径的模式,如果要想实现这种模式,还需要服务端的相应支持。

下面再来看一下两者原理上的区别。

Hash模式是基于锚点,以及onhashchange事件。

通过锚点的值作为路由地址,当地址发生变化后触发onhashchange事件。

History模式是基于HTML5中的History API

也就是如下两个方法

history.pushState( ) IE10以后才支持

history.replaceState( )

因为浏览器在刷新页面时,它会向服务器发送 GET 请求,但此时服务器并没有配置相应的资源来匹配这个请求,因此返回 404 错误。

2、解决方案
为了解决这个问题,我们需要在服务器端进行相关配置,让所有的路由都指向同一个入口文件(比如 index.html),由前端路由来处理 URL 请求,返回对应的页面内容。

具体的配置方式取决于对应项目使用的服务器环境,常见的有 Apache、Nginx 等。

以 Nginx 为例,需要在服务器配置文件(通常是 nginx.conf.js )中添加以下配置,以将所有请求都代理到 Vue 应用程序的入口文件:

try_file $uri$uri/ index.html

这段代码会将所有请求都指向根目录下的 index.html 文件,让前端路由来处理 URL 请求。

同时需要注意在使用 History 模式时,需要保证所有路由的访问路径都指向 index.html,否则仍然会出现404错误。

这些配置将确保在 Vue 应用程序中使用 history 模式时,服务器能够正确地处理所有路由请求,并返回正确的页面。

13.2 History模式的使用

History模式需要服务器的支持,为什么呢?

因为在单页面的应用中,只有一个页面,也就是index.html这个页面,服务端不存在http://www.test.com/login这样的地址,也就说如果刷新浏览器,

请求服务器,是找不到/login这个页面的,所以会出现404的错误。(在传统的开发模式下,输入以上的地址,会返回login这个页面,而在单页面应用中,只有一个页面为index.html)

所以说,在服务端应该除了静态资源外都返回单页应用的index.html

下面我们开始history模式来演示一下对应的问题。

首先添加一个针对404组件的处理

首先在菜单栏中添加一个链接:

      <div class="content left">
        <ul>
          <li><router-link to="/users"> 用户管理</router-link></li>
          <li><router-link to="/rights"> 权限管理</router-link></li>
          <li><router-link to="/goods"> 商品管理</router-link></li>
          <li><router-link to="/orders"> 订单管理</router-link></li>
          <li><router-link to="/settings"> 系统设置</router-link></li>
          <li><router-link to="/about"> 关于</router-link></li>
        </ul>
      </div>

这里我们添加了一个“关于”的链接,但是我们没有为其定义相应的组件,所以这里需要处理404的情况。

const NotFound = {
template: <div> 你访问的页面不存在!! </div>,
};

在程序中添加了一个针对404的组件。

const router = new VueRouter({
mode: “history”,
const router = new VueRouter({
mode: “history”,
routes: [
{ path: “/login”, component: Login },
{ path: “*”, component: NotFound },
{
path: “/”,
component: App,
redirect: “/users”,
children: [
{
path: “/users”,
component: Users,
meta: {
auth: true,
},
// beforeEnter(to, from, next) {
// if (window.isLogin) {
// next();
// } else {
// next(“/login?redirect=” + to.fullPath);
// }
// },
},
{ path: “/userinfo/:id”, component: UserInfo, props: true },
{ path: “/rights”, component: Rights },
{ path: “/goods”, component: Goods },
{ path: “/orders”, component: Orders },
{ path: “/settings”, component: Settings },
],
},
],
});

在上面的代码中,指定了处理404的路由规则,同时将路由的模式修改成了history模式。同时,启用这里启用了其它的组件的路由规则配置,也就是不在login方法中使用addRoutes方法来动态添加路由规则了。

login 方法修改成如下形式:

login() {
// window.isLogin = true;
window.sessionStorage.setItem(“isLogin”, true);
if (this.KaTeX parse error: Expected '}', got 'EOF' at end of input: … // this.router.addRoutes([
// {
// path: “/”,
// component: App,
// redirect: “/users”,
// children: [
// {
// path: “/users”,
// component: Users,
// meta: {
// auth: true,
// },
// // beforeEnter(to, from, next) {
// // if (window.isLogin) {
// // next();
// // } else {
// // next(“/login?redirect=” + to.fullPath);
// // }
// // },
// },
// { path: “/userinfo/:id”, component: UserInfo, props: true },
// { path: “/rights”, component: Rights },
// { path: “/goods”, component: Goods },
// { path: “/orders”, component: Orders },
// { path: “/settings”, component: Settings },
// ],
// },
// ]);
this. r o u t e r . p u s h ( t h i s . router.push(this. router.push(this.route.query.redirect);
} else {
this.$router.push(“/”);
}
}

现在已经将前端vue中的代码修改完毕了,下面我们要将页面的内容部署到node.js服务器中。

而且上面的代码中,我们使用了sessionStorage来保存登录用户的信息,不在使用window下的isLogin

对应的data内容下的代码也要修改:

const Login = {
data() {
return {
isLogin: window.sessionStorage.getItem(“isLogin”),
};
},

路由守卫中的代码进行如下修改:

jsrouter.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
if (window.sessionStorage.getItem(“isLogin”)) {
//用户已经登录
if (to.path === “/login”) {
// 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
next(“/”);
} else {
//用户已经登录,并且访问其它页面,则运行访问

        next();
      }
    } else {
      //用户没有登录,并且访问的就是登录页,则运行访问登录页
      if (to.path === "/login") {
        next();
      } else {
        //用户没有登录,访问其它页面,则跳转到登录页面。
        next("/login?redirect=" + to.fullPath);
      }
    }
  });

在上面的代码中,我们也是通过sessionStorage来获取登录信息。

index.html完整代码如下:

基于vue-router的案例

当然,项目的目录结构做了一定的调整,如下图所示:

在web目录下面,存放的是index.html,在webserver目录下面存放的是node代码。

下面看一下具体的node代码的实现。

app.js文件中的代码如下:

const path = require(“path”);
//导入处理history模式的模块
const history = require(“connect-history-api-fallback”);
const express = require(“express”);
const app = express();
//注册处理history模式的中间件
// app.use(history())
//处理静态资源的中间件,处理web目录下的index.html
app.use(express.static(path.join(__dirname, “…/web”)));
app.listen(3000, () => {
console.log(“服务器开启”);
});

connect-history-api-fallback模块的安装如下(注意在上面的代码中还没有使用该模块)

npm install --save connect-history-api-fallback
1
下面还需要安装express

npm install express
1
启动服务

node app.js
1
现在在地址栏中输入:http://localhost:3000就可以访问网站了。

并且当我们去单击左侧的菜单的时候,可以实现页面的切换,同时单击“关于”的时候,会出现NotFound组件中的内容。

经过测试发现好像没有什么问题,那这是什么原因呢?你想一下当我们单击左侧菜单的时候,路由是怎样工作的呢?

因为现在我们开启了路由的history模式,而该模式是通过HTML5中的history中的api来完成路由的操作的,也就是当我们单击菜单的时候,是通过history.pushState( ) 方法来修改地址栏中的地址,实现组件的切换,而且还会把地址保存的历史记录中(也就是可以单击浏览器中后退按钮,实现后退等操作),但是它并不会向服务器发送请求。

所以说现在整个操作都是在客户端完成的。

但是,当我刷新了浏览器以后,会出现怎样的情况呢?

上图的含义就是,当单击浏览器中的刷新按钮的时候,会向服务器发送请求,要求node服务器处理这个地址,但是服务器并没有处理该地址,所以服务器会返回404

以上就是如果vue-router开启了history模式后,出现的问题。

下面解决这个问题,在服务端启用connect-history-api-fallback模块就可以了,如下代码所示:

const path = require(“path”);
//导入处理history模式的模块
const history = require(“connect-history-api-fallback”);
const express = require(“express”);
const app = express();
//注册处理history模式的中间件
app.use(history());
//处理静态资源的中间件
app.use(express.static(path.join(__dirname, “…/web”)));
app.listen(3000, () => {
console.log(“服务器开启”);
});

服务端的代码做了修改以后,一定要服务端重新启动node app.js

然后经过测试以后发现没有问题了。

那么现在你考虑一下,具体的工作方式是什么?

当我们在服务端开启对history模式的支持以后,我们刷新浏览器,会想服务器发送请求,例如:http://localhost:3000/orders

服务器接收该请求,那么用于服务器开启了history模式,然后服务器会检查,根据该请求所访问的页面是不存在的,所以会将单页面应用的index.html返回给浏览器。浏览器接收index.html页面后,会判断路由地址,发现地址为orders,所以会加载该地址对应的组件内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值