前端存储
转载请注明出处:unclekeith: 前端存储
前端存储是每个前端开发工程师必备的技能。废话不多说了,直接进入主题。
以下总结有关前端存储方面的知识。主要是Cookie与WebStorage。当然,对于这两种存储方式的介绍,会与前端安全的问题一起讨论
- Cookie
- Cookie定义
- Cookie组成
- Cookie大小
- Cookie用途
- Cookie缺点
- Web Storage
- Storage原型对象
- sessionStorage对象
- localStorage对象
- Storage事件
- IndexedDB
Cookie
Cookie定义:
Cookie,中文名称为'小型文本文件'或'小甜饼',指某些网站为了辨识用户身份而存储在用户本地终端上的数据(通常name和value经过编码)。
Cookie组成:
Cookie主要由以下几个字段组成:
Cookie: [name][value][domain][path][expires][httpOnly][secure]
通常通过JS设置Cookie为以下形式。当然,最好的方式是通过一个函数来设置。
document.cookie = 'name=kk; domain=localhost; path=/; expires= Mon Nov 06 2017 01:32:07 GMT+0800 (CST)'
name, value: 是Cookie的名称和值。Cookie的name和value必须经过url编码。在JS中可以通过window.encodeURIComponent
方法来对name和value进行编码。同时,在写cookie的时候要注意,cookie的名称是不区分大小写的。所以myCookie和MyCookie被认为是同一个cookie。但是在实际开发过程中,最好区分大小写。
domain: Cookie对于哪个域是有效的。所以向该域发出的请求都会包含Cookie信息。设置Cookie时,如果不指定Cookie的值,默认就是本域名。如我在本地通过Node.js起服务器时,Cookie的domain为domain=localhost
。
子域可以获取当前域(父域)的cookie,但是当前域(父域)不能获取子域的cookie。比如说,当前域为a.com,在a.com设置了cookie。那么其子域b.a.com可以获取a.com的cookie。但是如果在b.a.com设置的cookie,在a.com域名下不能获取到b.a.com下的cookie。
path: 对于指定域中的那个路径,应该向服务器发送cookie。默认情况下,如果不设置Cookie的path时,默认路径为/。比如说,在a.com/profile路径下设置的cookie,那么在访问此路径的时候才会发送cookie,在访问a.com时不会发送cookie。
如果需要跨路径获取Cookie值,可以使用隐藏的iframe实现,但是必须是同源的。
expires:表示Cookie何时被删除的时间戳。这个时间戳是GMT格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT)。如果设置成以前的时间,则Cookie会被立即删除。如果设置的是将来的某个时间,那么即使关闭浏览器,cookie仍然保持在用户的电脑上。expires字段的设置与否,会把Cookie分为两种:本地(持久化)Cookie和内存(非持久化)Cookie。在介绍分类的时候再细说。
httpOnly: 顾名思义,httpOnly是指在HTTP层面上传输的Cookie。当服务端对Cookie消息设置了httpOnly标志之后,客户端脚本就无法通过document.cookie
的方式读写cookie。能够读取意味着可以获取Cookie,能够写入Cookie意味着可以篡改Cookie。因此,对重要的Cookie消息设置httpOnly能够有效防御XSS攻击获取Cookie。
secure: secure表明设置了secure字段的Cookie只能在HTTPS上进行安全数据传输。如果请求是HTTP的,就不会带上这个Cookie。这里要留心一点的是,服务端设置cookie下的secure字段,它并不是以名称-值对的形式的。而是单单一个secure单词。例如,Cookie信息只能发送给https://keith.com,而http://keith.com的请求则不能发送Cookie。
如以下响应头,其他字段是名称-值对的形式,而secure是一个单词。
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: name=keith; domain=localhost; path=/; exipres=Mon, 08-June-18 07:10:24 GMT; secure
但是,有一个很特别的是设置了secure字段的Cookie可以被读写。因此,一般情况下,如果只允许HTTPS获取数据,服务端可以一起配置secure + httpOnly字段,这样就能够保证HTTPS传输,并且避免了Cookie被读写的风险。
Cookie大小:
大多数浏览器Cookie默认大小为4kb。超过的部分会被截断掉。
Cookie分类:
根据Cookie中的expires字段,可以将Cookie分为本地(持久化)Cookie和内存(非持久化)Cookie。
当expires没有设置时,实际上就相当于一个内存Cookie。浏览器关闭之后就消失了。同时,在当前浏览器下,打开多个页面仍然可以访问到Cookie消息。也就是说,如果浏览器不关掉的情况下都会发送Cookie。
当expires设置一个未来的时间,那么就是一个本地Cookie。此时会将Cookie存入到操作系统本地,待过期时间到了才会消失。
因此根据expires字段,可以利用Cookie做用户登录认证、购物车信息存储等功能。
Cookie用途:
当登录一个网站的时候。
- 客户端会将登录的账号和密码发送到服务器。
- 服务器对账号和密码进行加密算法之后生成session文件,然后会在响应时将set-cookie带在响应头。
- 客户端接着会将cookie保存在内存中。
- 客户端下次请求的时候,会将cookie作为请求头发往服务器。
- 服务器将对客户端传过来的cookie与session文件进行校验,如果校验通过,则可以直接登录。
在购物场景中。
- 客户端会将用户已经选购的商品1发往服务器。
- 服务器会生成一份session文件,在响应时带上set-cookie发往客户端。
- 客户端会保存服务端传来的cookie.
- 用户再次选择商品2,进行以上同样的操作。
- 此时用户需要结账,客户端会将cookie发往服务器
- 进入结账页面时就会出现两个商品。
Cookie缺点:
1.Cookie的大小限制在4kb左右。对于复杂的存储来说是不够的
2.Cookie会被附加在每个HTTP请求中,所以会增加HTTP请求大小
3.由于Cookie都是在HTTP请求中明文传递的,会有安全性问题(除非使用HTTPS)
Web Storage
Storage原型对象
sessionStorage和localStorage对象都是继承自Storage原型对象的。在Storage对象中存在以下方法
clear(): 清除所有storage
setItem(name, value): 设置storage, 也可以通过点语法或者方括号设置
getItem(name): 获取name对应的value值, 也可以通过点语法或者方括号获取
removeItem(name): 删除单个storage。 也可以通过delete操作符删除
key(index): 获取index位置处的name
sessionStorage
sessionStorage存储大小为5MB(大多数浏览器)。它属于一种非持久化数据,在浏览器关掉时数据就消失了。同时,在浏览器未关闭,而重新开一个页面(切换了路径),也是无法访问到sessionStorage的。因此在多页面应用时有限制。可以使用localStorage来代替。
由于sessionStorage是对象,所以可以通过for-in语句或者结合length属性来遍历每个storage值,对于localStorage对象来说也是适用的。
// 方法一
for (let key in window.sessionStorage) {
let value = window.sessionStorage[key]
console.log(`${key}=${value}`)
}
// 方法二
for (let i = 0; i < window.sessionStorage.length; i++) {
let key = window.sessionStorage.key(i)
let value = window.sessionStorage[key]
console.log(`${key}=${value}`)
}
localStorage
localStorage的存储大小也为5MB(大多数浏览器)。localStorage会存储在本地操作系统的文件中。在数据时效性上,localStorage并不会想cookie那样可以设置数据的过期时间。也就是说,只要用户不主动删除localStorage,localStorage存储的数据将会永久存在。
注意,localStorage无法跨浏览器存在。
这样介绍一个看,localStorage即比Cookie拥有更大的数据存储空间,而且数据也是持久化的,不会随着网页的关闭而消失,好像可以代替Cookie来做用户身份验证。
其实是不能的。我们知道,通常可以通过XSS漏洞来获取到Cookie,然后用这个Cookie进行身份验证登录。但是为了防止通过XSS获取到Cookie数据,服务器可以配置httpOnly来保护Cookie,禁止浏览器通过脚本document.cookie
获取到Cookie。而localStorage存储没有对XSS攻击有任何的防御机制,一旦出现XSS漏洞,那么存储在localStorage里的数据(如重要的用户名、密码)就极容易被获取到。因此重要的信息不要存储在storage对象中。
Storage事件
在改变sessionStorage对象或者localStorage对象之后,就会触发Storage事件。也就是说,当删除、修改、设置storage时,都会调用Storage事件。Storage事件的事件对象存在以下属性。
domain: 发生变化的存储的域名
key: 设置或删除的键名
newValue: 如果是设置值,则对应一个新值;如果是删除值,则是null
oldValue: 键值被修改前的值
document.addEventListener('storage', (e) => {
console.log(e.domain)
console.log(e.key)
console.log(e.newValue)
console.log(e.oldValue)
}, false)
IndexDB
这个目前我暂时还没有用过....先占位,用过之后再回来填坑