Cookie、Session 存储技术

保存用户和网站之间的一个状态。

  • Cookie(复数形态Cookies),中文名称为“小型文本文件”或“小甜饼”
  • 指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
  • 是网景公司的前雇员卢·蒙特利在1993年3月的发明
  • 历史记录是浏览器的一个特性,cookie 使用了保持状态的一种手段
  • 浏览器缓存分为好几种
    • 一般所指缓存有静态资源缓存:
      • css、img、JavaScript
      • 不是经常变换的资源可以设置环境
      • 也不是浏览器能做到的
      • 304 服务器做的
    • 动态资源缓存
      • 浏览器可以做到
      • 例如不常变化的接口资源
      • 例如商品分类

HTTP 无状态

  • 跟客户端交互,到底做了什么事情,对于服务器来说根本就不知道

  • 为什么不记住客户端跟我做了什么事情?

    • 客户端第一次请求过来
    • 服务器校验一下客户端有没有那个标记(Cookie凭证)
      • 如果发现有,则不给标记
      • 如果发现没有:写Cookie(贴凭证)

所谓的 Cookie 其实就是服务器和客户端浏览器约定好的一种规则。
只要服务器给客户端浏览器发送了一个 Cookie,则浏览器以后的每次请求中都会自动带着这个 Cookie 上来。

Cookie 就是通过 HTTP 请求报文和响应报文配合完成。

如何使用

利用响应头:Set-Cookie 来写 Cookie,然后解析请求头中的 cookie 来读取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const http = require('http');
// 是不是第一次访问网站
// 如果是第一次访问:告诉用户是第一个访问该网站
// 如果不是第一次访问:告诉用户欢迎再次访问
http.createServer()
.on('request', (req, res) => {
// 如果你给客户端发送过这个 Cookie 了
// 则客户端请求的时候会自动带过来
// 然后将 Cookie 放到请求报文中
const cookies = req.headers['cookie'];
req.cookie = {};
if (cookies) {
cookies.split(';').forEach(cookie => {
const tmp = cookie.split('=');
req.cookie[tmp[0]] = tmp[1];
});
}
if (req.cookie.isFirst) {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8',
});
res.end('欢迎再次光临...');
} else {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8',
'Set-Cookie': 'isFirst=true; Max-Age=20;',
});
res.end('欢迎第一次访问');
}
});
.listen(4000, () => {
console.log('runnning...');
});
1
2
3
4
5
6
7
8
9
10
11
12
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script src="/node_modules/js-cookie/src/js.cookie.js"></script>
<script>
var username = Cookies.get('username');
if (username) {
document.querySelector('#username').value = username;
}
$('form').on('submit', function (e) {
e.preventDefault();
Cookies.set('username', $('#username').val());
});
</script>

安装:

1
$ npm install --save cookie-parser

配置:

1
2
3
4
5
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
// 配置中间件
app.use(cookieParser());

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
// 只要在 Express 中配置了这个中间件,使用 Cookie 解析中间件。
app.use(cookieParser());
app.get('/', (req, res) => {
// req.cookies 用来获取请求中的 Cookie
if (req.cookies.isFirst) {
res.send('欢迎再次访问本网站');
} else {
// 第三个参数设置过期时间
res.cookie('isFirst', 'true', {
maxAge: 10 * 1000
});
res.send('欢迎第一次访问');
}
});
app.listen(3000, () => {
console.log('running...');
});
  • 会话 Cookie,也叫 内存 Cookie,存在于浏览器运行的进程中

    • 只要浏览器一关闭,Cookie 就会被销毁
  • 持久化 Cookie

    • 持久化 Cookie 会保存在磁盘上
    • 通过过期时间来设定持久 Cookie 的保存时间
  • 购物车
    • 没有登陆之前商品数据是保存到 Cookie 中了
  • 记住用户名
    • 利用 Cookie 保存用户名
  • 记住我
    • 利用 Cookie 来保存用户名和密码(加密之后保存的)

Cookie 一般适用于安全性要求不高的场景。

  • Cookie体积过大会造成请求和响应速度变慢
    • 尽量不要再Cookie中存储大量数据
  • 默认浏览器会对任何请求把 Cookie 带上去
    • 哪怕是静态资源:/public/css/main.css
    • 所以说在静态资源请求中带着 Cookie 上去,没有意义,影响性能
    • 一般大型网站会专门把静态资源存储到单独的域名服务器上
  • Cookie可以在前后端修改,数据容易被篡改和伪造
  • Cookie对于敏感数据的保护基本是无效的
  • Cookie 就是保存状态数据的。

session

Session 是基于 Cookie 的。Cookie 是 session 的凭证。

在 Express 中使用 express-session 中间件

session原理

安装:

1
$ npm install --save express-session

配置:

1
2
3
4
5
6
7
8
const session = require('express-session');
// secret 就是私钥,生成钥匙的时候会根据这个私有加密,用来访问别人伪造钥匙
app.use(session({
secret: 'hq',
resave: false,
saveUninitialized: true
}));

基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const express = require('express');
const session = require('express-session');
const app = express();
// secret 表示生成钥匙的时候根据这个字符串生成
// 这个字符串一般被称为私钥
app.use(session({
secret: 'mhq',
resave: false,
saveUninitialized: true
}));
app.get('/', (req, res) => {
// 只要配置了 Session 中间件
// 那么,客户端请求过来就会直接给其分配一把钥匙,在本次请求会话过程中都是同一个
// Session 也分为会话 Session 和 持久 Session
// 没有配置 Session 中间件之前 req 对象是没有 session 这个属性的
// 配置完毕之后,req 请求对象会多出一个 Session 属性出来
// req.session 就是根据客户端的凭证找到其对应的数据
// console.log(req.session);
// session 数据是保存在当前运行的 node 进程中的,也就是保存在内存中
// 只要服务器重启,或者服务器宕机了,则 Session 数据丢失
if (req.session.isLogin) {
res.send('欢迎再次访问');
} else {
// 通过客户端的 Cookie 钥匙凭证,找到对应的数据格子
// 找到数据格式之后,往里面加一个属性:isLogin
req.session.isLogin = true;
res.send('欢迎第一次访问');
}
});
app.get('/logout', (req, res) => {
// 清除 Session 中的数据
req.session.isLogin = null;
res.send('用户退出了');
});
app.listen(3000, () => {
console.log('running...');
});

总结

Cookie虽在持久保存客户端数据提供方便并分担服务器存储负担,但有很多局限性

  • 弊端
    • IE6 或更低的版本最多 20 个 cookie
    • IE7 和之后的版本最后可以有 50 cookie
    • FireFox 最多 50 个 cookie
    • chrome 和 Safari 没有做硬性限制

IE 和 opera 会清理近期最少使用的 cookie,FireFox 会随时清理 cookie,cookie 的最大容量为 4096 字节,为了兼容性,一般不能超过 4095

IE 提供了一种存储可以支持持久化用户数据,叫做 userdata ,从 IE5.0 就开始支持。每个数据最多 128k ,每个域名下最多 1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。

  • 优点:极高的扩展性和可用性
    • 通过良好的编程,控制保存在 cookie 中的 session 对象的大小
    • 通过加密和安全传输技术(SSL),减少 cookie 被破解的可能性
    • 只要在 cookie 中存放不敏感数据,即使被盗也不会有重大损失
    • 控制 cookie 的生命周期,使之不会永远有效。偷盗者很可能拿到一个过去的 cookie
  • 缺点
    • cookie 数量和长度的限制。每个 domain 最多只能有 20 条 cookie ,每个 cookie 的长度不能超过 4kb,否则被截掉;
    • 安全性问题。如果 cookie 被拦截了,那么拦截者就可以取得所有的 session 信息。即使密码加密也于事无补,因为拦截者并不需要知道 cookie 的意义,他只要原样转发 cookie 就可以达到目的了;
    • 有些状态不可能保存客户端。例如:为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。

浏览器本地存储

在较高版本浏览器中,JavaScript 供了 sessionStorage 和 globalStorage ,在 HTML5 中提供了 localStorage 来取代 lobalStorage

H5 中的 web Storage 中包括两种存储方式:sessionStorage 和 localStorage

sessionStorage和localStorage区别

sessionStorage 和localStorage 都有相同的方法,例如:setItem, getItem, removeItem, clear

sessionStorage 用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也会随之消失。因此,sessionStorage 不是一种持久化的本地存储,仅仅是会话级别的存储。

localStorage 用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

web Storage 和 cookie 相似,web Storage 的存储更大;

cookie 大小受限,并且每次新请求一个页面 cookie 都会发送过去,浪费了带宽;

cookie 还需要指定作用域,不可以跨域调用;

cookie 是不可缺的:其作用是与服务器进行交互,作为 HTTP 规范的一部分二存在,而 Web Storage 仅仅是为了在本地“存储”数据而生。

web Storage方法:

setItem, getItem, removeItem, clear等方法,而 cookie 需要开发者自己封装 setCookie, getCookie。

浏览器的支持

浏览器的支持除了IE7以下不支持外,其他标准浏览器都完全支持(IE及FF需要在web服务器里运行)。

IE6,7中的 userDat a其实就是 javascript 本地存储的解决方案。通过简单封装代码就可以使所有的浏览器都支持 Web Storage。

cookie 数据存储在客户的浏览器上,session 数据放在服务器上;

cookie 数据不安全,别人可以分享存放在本地的 cookie 并进行 cookie 欺骗,考虑到安全性应当使用 session;

session 一般会在一定的时间内保存在服务器上。当访问增多,会比较占用服务器的性能;

单个 cookie 保存的数据不能超过 4k,很多浏览器都限制一个站点最多保存 20 个 cookie;

个人等数据存放为 session 稳妥;其他数据可以存放到 cookie 中。

总的来说:

cookies 兼容所有的浏览器,Html5 提供的storage 存储方式。

  • Document.cookie
  • Window.localstorage
  • Window.sessionstorage
  1. cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递。而 sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存。
  2. 存储大小限制也不同,cookie 数据不能超过 4k,同时因为每次http请求都会携带 cookie ,所以 cookie 只适合保存很小的数据,如会话标识。sessionStorage 和 localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到 5M 或更大。
  3. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie 只在设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭。
  4. 作用域不同,sessionStorage 不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的。
感谢您的支持!