业务背景
由于项目使用微前端(qiankun) 基座服务承载技术中台的角色,用户可通过技术中台定制菜单等等,子服务只需要提供业务服务与基座服务进行关联,使得前端路由不得不采用history路由,如果使用hash路由,会导致基座服务在切换菜单的时候出现页面切换问题,未重新获取路由地址,导致页面无法正常切换。
产品期望只提供一个前端服务,子服务不仅仅要提供给基座服务使用,并且还要提供第三方嵌套(iframe),在考虑到使用history路由的时候, 遇到一个很郁闷的问题, 页面刷新之后 what??? 直接空白!!
在此之前 我们可以了解一下hash和history的差异性:
- hash 在地址栏 URL 中的 # 符号。比如这个 URL:www.baidu.com/#/hello hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
- history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
解决方案
- sessionStorage 或者 localStorage 估计很多小伙伴第一时间想到的方式是,在页面首次加载之后,把数据保存到sessionStorage 或者 localStorage 当中, 但是这种方案是有局限性的,比如接口数据返回过多的情况下,这种方案是不可取的。
可以看到接口返回的数据已经超过5M, 所以在这种场景下,不能使用sessionStorage 或者 localStorage。
- 服务端Nginx配置
location / {
try_files $uri $uri/ /index.html;
}
- webpack配置文件中的publicPath属性
module.exports = {
publicPath: process.env.NODE_ENV === "production" ? "/site/vue-demo/" : "/", //路径从 "./" 修改成 "/"
}
通过修改路径的方式,即使是在history路由下,刷新页面依然能够正常访问,不会出现页面404 或者接口500的情况, 不过需要注意的是强缓存和协议缓存。
强缓存和协议缓存
强缓存相关字段有 expires, cache-control。 如果 cache-control 与 expires 同时存在的话, cache-control 的优先级高于 expires。
协商缓存相关字段有 Last-Modified/If-Modified-Since,Etag/If-None-Match
强缓存 200 不会发送请求到服务器 直接取本地缓存
协议缓存 304 发送请求到服务器 通过服务器来告知缓存是否可用
Cache-Control 使用相对时间
Expires 使用的是基于服务器端的绝对时间,因为存在时差问题,一般采用 Cache-Control
cache-control 是一个通用消息头字段被用于 HTTP 请求和响应中,通过指定指令来实现 缓存机制,这个缓存指令是单向的,常见的取值有 private、no-cache、max-age、 must-revalidate 等,默认为 private。
总结
在这种场景下,我们需要对路由的差异性、以及存储方式的理解,同时需要考虑到的是,如果客户端能够提供解决的方案的情况下,不能直接把问题抛给服务端,当然这要结合场景以及性能安全等等因素。