关于网页本地存储的一些思考

更新日期: 2018-03-16阅读: 3.7k标签: 存储

前言

关于localStorage sessionStorage之类的api怎么用已经无需我再赘述了,但是具体怎么落实到一个稍微复杂一些的业务中还是需要做一些前期的准备


遇见的一些问题

1.localStorage 与 sessionStorage具体适用于什么样的业务场景?
2.如何维护本地储存?
3.如何进行版本控制?
4.碰到禁止本地缓存的情况下怎么解决这个问题?


常见情况

根据本身特性localStorage做长期存储, sessionStorage做临时存储大家都是清楚的也无需赘述,至于IndexedDB之类的暂时不做讨论。
很多初级的前后端分离的项目习惯性误区是把用户token存到localStorage。
这时候碰到一个问题:

如果需要在不同域名下做登陆信息共享该怎么办?

常见做法是SSO,同一个域名下的小型项目用cookies的domain直接来做简单的跨域共享也是一个办法,而这个时候localStorage和sessionStorage就出现业务盲点了。
不仅过不去,即使通过各种鬼畜的操作过去了后面擦屁股也麻烦的要死:

  1. 登陆了以后用户信息怎么传给别的域名?
  2. 退登的话怎么删除所有页面的登陆状态?

当然如果需要实现还是比较依赖后端的用户登陆状态判定,而这个时候某些分离得过分干净的业务可能出现一些诡异的状态判定,比如a.xxx.com站退登了b.xxx.com站还登着,你要真要前端来做这事代码量也是相当可观的,甚至各个页面缓存的token数据可能还都不一样,显然不够合理也不适合这样用,请把后端的事情还给后端,除非前端也写一些node中间层。
而且某些浏览器的无痕功能禁用了localStorage和sessionStorage导致登陆状态异常,所以localStorage存用户token的事情就把它忘记吧,不然后面就等着哭吧。


那么存什么好呢?

存些不常变的东西?
比如图片,把图片转成base64再存起来?
那么问题来了,一般我们会存什么图片?
比如一些背景图?
那么为了这件事情我们首次载入的时候先要把图片下载过来,然后费尽心思存起来还要避免和别的同事重名,万一哪天要换个图片还要想办法把之前的内容清理掉不然直接读localStorage里的内容,即使做好了本地存储的版本控制还要专门写一大堆代码增删改查,这明显是嫌自己工作量不够大,本来只要用cdn直接解决的东西被搞得这么费劲,何必呢?
所以存文件的事情基本也可以忽略了。

还有一些神奇的做法是存js代码,敢这样做的人不是蠢就是坏了。

然后,一般localStorage常用于缓存一些内容很多很固定的数据比如全国各地省市县、区号之类的基本不会变但又会在各种ui组件里用到的简单数据,但是直接JSON.parse然后还去遍历一个很大的数据做查询筛选只会让你的机器感到绝望发红发烫濒临崩溃,而这个时候我还不如直接用cdn载入一个专门用于存放这类静态数据的js文件来得快捷方便性能还好还能随时改。

难道localStorage真的这么废?

其实也不是啦,首先要确定一点,不去存过大的JSON数据,那就存个小的:

  1. 用户搜索历史的缓存。
  2. 文本编辑器内输入的内容。

然后是sessionStorage,其实我最喜欢用这个了,关掉就清除毫无后顾之忧,那一般我会用于什么业务场景呢:

  1. 存网页的历史记录,操作过histroyAPI的朋友一定知道为了避免安全性问题histroy只会给你当前页面前面打开过几个页面的数量。所以完全可以在这里做个histroy的详细记录,甚至结合spa项目的router插件来满足各类奇怪的需求,比如跳了好几次页面填了一堆表格后点击支付然后支付完成后即使点击浏览器顶部的后退按钮也能直接一脚跨回首页。
  2. 或者存那堆临时表格的内容(2B业务经常碰到那种填一大堆又臭又长的申请表还要经过各种审批的功能)
  3. 存用户个人信息,比如用户昵称之类的,不用每次刷新都去服务器拖一遍(当然这种事情其实还是有一定风险的,万一用户在别的地方改昵称了,你还得想办法同步,具体解决办法后面说)


怎么存?

很多人第一反应可能是直接使用 localStorage.setItem之类的api
一旦你真的只这样做了...我可能无法保证你不被同事揍


入口

每个业务线本身应该有个状态的管理区域,而这些业务线的本地数据存储业务应该汇总入到一个公共的入口做类型判定以及进行增删改查。
一般比如vue的应用,我们会把数据存到Vuex的state内,每个业务线分支都会有单独的模块引入并进行独立维护。


命名

你必须确定一个习惯一致,名字唯一的命名协议。
自娱自乐的项目也就罢了,万一是个超过四个人的前端小队每年可能都有不同的人会离职不同的人会入职不同的业务要迭代不同的功能要修改,增删改查的事情如果没有一个确定的标准后果不堪设想。
一般常见命名方式会在前面带入业务模块名称
比如 USER_INFORMATION_NICKNAME 之类的,当然有的信息可能不方便透露只写个索引名称也是有的,主要还是看公司里决定这个规则的人怎么考虑。


增删改查

还是以Vuex做为例子(以下内容仅供参考,请勿直接用于业务代码中)

在State中声明对象用于获取本地存储内容的元数据

state:{
  NICKNAME: window.localStorage.getItem('USER_INFORMATION_NICKNAME')
}

创建一个Getter用于内容读取

getters: {
  USER_INFORMATION_NICKNAME: state => {
    try {
      return JSON.parse(state.NICKNAME)
    } catch (e) {
      localStorage.removeItem('USER_INFORMATION_NICKNAME')
      return  null
    }
 }
}

写入Mutation用于增删改

mutations: {
  DELETE_USER_INFORMATION_NICKNAME (state) {
    window.localStorage.removeItem('USER_INFORMATION_NICKNAME')
    state.USER_INFORMATION_NICKNAME = value
  },
  UPDATE_USER_INFORMATION_NICKNAME (state, value) {
    window.localStorage.setItem('USER_INFORMATION_NICKNAME', value)
    state.USER_INFORMATION_NICKNAME = null
  }
}

写入Action用于信息同步

actions: {
  GET_USER_INFORMATION_NICKNAME:context => {
    $http
    .get('xxx')
    .then(res=> {
      context.commit('UPDATE_INFORMATION_NICKNAME', res)
    })
    .catch(e => xxx...)
 }
}

这样一个最最最基本的读取策略已经完成了。
但问题又来了


怎么删?什么时候删?

毕竟是永久缓存,版本控制非常重要,不然就是给自己挖坑
首先要明确删除数据的具体场景

  1. 可能是只存一小段时间后就失效的内容
  2. 可能是下个大版本会被迭代掉的内容
  3. 可能会发起部分用户要升级部分用户维持现状甚至因为新版本业务不够完善可能需要回滚的灰度更新。

一般情况下我们需要在getter内先确定一个数据读取的依赖项,读取的内容可能是跟着依赖项数据走也可能不跟着依赖项数据走,这个看具体业务需求,如果不跟着依赖项走或者本身就是被依赖的项目的话就需要确定几件事情

  1. 版本
  2. 过期时间

可能该内容依赖于父级项 0.0.1版本的内容,超过或者低于这个版本都可能出现问题需要及时删除并重新获取
可能当前载入的页面中的配置项的版本与自身版本不一致所以需要移除并更新数据
于是导致的结果是我们需要再去声明一个不保存在本地的配置JSON

{
  "USER_INFORMATION": {
    "NICKNAME": "1.1.1",
    "AGE": "1.1.2"
    ...
  }
}

如果要进行灰度更新的话,这个配置就需要写入到接口里面了。
还有个情况就是设置过期时间,超出这个限定的时间就清空数据。
于是我们就需要在UPDATE方法内多写入些东西

UPDATE_USER_INFORMATION_NICKNAME (state, value) {

  const new_value = {
    expires: Date.now() + 24 * 1000 * 30 * 3600,
    version: state.config.USER_INFORMATION.NICKNAME,
    value: value
  }

  window.localStorage.setItem('USER_INFORMATION_NICKNAME', JSON.stringify(new_value))
  state.USER_INFORMATION_NICKNAME = new_value
}

再调整下读取的逻辑,
其他的代码也跟着做一遍调整,依照自己能力水平能封装的封装,能复用的复用。
于是一个拥有版本控制和过期控制的本地内容存储功能模块就算初步完成了。
做完这一切虽然感觉好像是像那么回事了


直到用户突然开启了无痕模式....

后面的问题也只是封装业务中的判断逻辑罢了...
所以,有一个健壮的前端数据流才是核心,其他的只不过是帮助页面达到更好的体验的辅助功能罢了,东西再好也不能滥用。


转载来源:https://segmentfault.com/a/1190000013768365
作者:MaxChan

链接: https://www.fly63.com/article/detial/510

js中cookie操作总结:cookie设置,读取,删除,判断是否存在

有时也用其复数形式 Cookies,指某些网站为了辨别用户身份,JavaScript对cookie的相关操作,设置cookie,读取cookie,删除cookie,判断cookie是否存在.......

HTML5新方法:前端存储localStorage的使用总汇

在HTML5中有一个localStorage的新特性,它主要用于本地存储使用,目的是为了解决了cookie存储空间小的问题。本文将讲解:localStorage特点、localStorage的兼容、localStorage的使用等

Token ,Cookie和Session的区别

在做接口测试时,经常会碰到请求参数为token的类型,但是可能大部分测试人员对token,cookie,session的区别还是一知半解

介绍web开发中实现会话跟踪的常用技术方法

由于http是无状态的协议,这种特性严重阻碍了客户端与服务器进行动态交互,为了弥补http的不足,目前实现会话跟踪的常用技术方法:cookie、session、url重写、隐藏input、ip地址。

JS中原始值和引用值的储存方式

在ECMAscript中,变量可以存放两种类型的值,即原始值和引用值。原始变量及他们的值储存在栈中,当把一个原始变量传递给另一个原始变量时,是把一个栈房间的东西复制到另一个栈房间,且这两个原始变量互不影响。

前端数据保存_使用js开发数据库

前端很多时候还是需要保存一些数据的,这里的保存指的是长久的保存。以前的思想是把数据保存在cookie中,或者将key保存在cookie中,将其他数据保存在服务器上。想要一种能够长久的保存在本地的数据,类似数据库或者类似web sql。

Cookie防篡改机制_cookie怎么防止被篡改/伪造

因为Cookie是存储在客户端,用户可以随意修改。所以存在一定的安全隐患,服务器为每个Cookie项生成签名。如果用户篡改Cookie,则与签名无法对应上。以此,来判断数据是否被篡改。

在前后端分离的项目中,ajax跨域请求怎样附带cookie

后台保存用户信息通常使用的session和cookie结合的方法,而在前端的实际情况中,跨域产生的ajax是无法携带cookie信息的,这样导致了session和cookie的用户信息储存模式受到影响,该怎样去解决这样一个问题呢

localStorage设置过期时间

我们都知道localStorage不主动删除,永远不会销毁,那么如何设置localStorage的过期时间呢?使用场景: 1.利用本地数据,减少网络传输 ,2.弱网络环境下,高延迟,低带宽,尽量把数据本地化

HTML5中的storage 如何使用

HTML5中,我们常常用到storage,那这个storage到底是什么?有啥用呢?其实,storage是个很简单的东西,只要熟悉JavaScript中对象的童鞋,看完小编本文的分享

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!