现代的前端框架react/vue/angular都有路由router的概念,通过手写实现可以帮助我们更好地了解它的工作原理。它们都推荐单页面应用 SPA 开发模式,在路由切换时替换 DOM Tree 中最小修改的部分 DOM,来减少原先因为多页应用的页面跳转带来的巨量性能损耗。它们都有自己的典型路由解决方案,@angular/router、react-router、vue-router等。
一般来说,这些路由插件总是提供两种不同方式的路由方式: Hash 和 History,有时也会提供非浏览器环境下的路由方式 Abstract(支持所有 JavaScript 运行 环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式)。
实现路由的2种方式
- hash模式 状态保存需要另行传递
- history模式 原生提供了自定义状态传递的能力
缺点
hash: 地址栏会多出一个#号,对url造成影响,在某些场景下如微信支付有坑。 history: 兼容性差,直接访问报404,需要服务器做处理。
基本原理
- hash 主要原理是通过监听 # 后的 URL 路径标识符的更改而触发的浏览器 hashchange 事件(当 location.hash 发生改变时,将触发这个事件)
注意: Hash 方法是利用了相当于页面锚点的功能,所以与原来的通过锚点定位来进行页面滚动定位的方式冲突,导致定位到错误的路由路径,因此需要采用别的办法。
- history 则基于 pushState 和 popState replaceState
Hash 模式是使用 URL 的 Hash 来模拟一个完整的 URL,因此当 URL 改变的时候页面并不会重载。History 模式则会直接改变 URL,所以在路由跳转的时候会丢失一些地址信息(只是动态的通过js操作window.history来改变浏览器地址栏里的路径,并没有发起http请求),在刷新或直接访问路由地址的时候会匹配不到静态资源。因此需要在服务器上配置一些信息,让服务器增加一个覆盖所有情况的候选资源。
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。
- 服务器配置
Nginx方式 采用Nginx方案需要先将所有资源打包生成到对应的目录,比如dist,然后做如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14server {
server_name react.thinktxt.com;
listen 80;
root /Users/txBoy/WEB-Project/React-Demo/dist;
index index.html;
location / {
// $uri 是 nginx 的变量,就是当前这次请求的路径
// try_files 会尝试在这个路径下寻找资源,如果找不到,会继续朝下一个寻找
// $uri/ 的意思是在路径目录下寻找 index.html 或 index.htm
// 最后都找不到的话,返回 index.html
try_files $uri $uri/ /index.html;
}
}通过修改webpack-dev-server运行方式 这个解决方法很简单,直接在运行时加入参数“–history-api-fallback”就可以了
Node服务端配置
1 | // express |
由于koa的这种方式端口与webpack-dev-server(8080)必须不同,所以还需要配合Nginx代理。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17server {
server_name react.thinktxt.com;
listen 80;
location / {
proxy_pass http://localhost:8081;
}
}
server {
server_name static.react.thinktxt.com;
listen 80;
location / {
proxy_pass http://localhost:8080;
}
}
既然我们的Nginx代理用了真实域名,自然别忘了修改一下host,如下:
1
2127.0.0.1 react.thinktxt.com
127.0.0.1 static.react.thinktxt.com
hash模式
1 | <html> |
history模式(需要服务器环境)
1 | <html> |