cookie-session

HTTP无状态的

不知道每次是哪里发过来的请求

  • cookie 是存放到 浏览器上的 ,服务器可以设置,每此请求时会带上cookie
  • cookie 不安全 不能存放敏感信息
  • session 服务端(基于cookie) 存放在服务器的内存中 或者=> redis 数据库 (get set)

新建cookie.js

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
40
41
42
43
44
45
46
// 基本的 设置cookie 和 获取cookie

const http = require('http');
const querystring = require('querystring');
http.createServer((req,res)=>{
let arr = [];
res.setCookie = function(key,value,options={}){
let opts = [];
if(options.domain){
opts.push(`domain=${options.domain}`)
}
if(options.maxAge){
opts.push(`max-age=${options.maxAge}`)
}
if(options.httpOnly){
opts.push(`httpOnly=${options.httpOnly}`)
}
arr.push(`${key}=${value}; ${opts.join('; ')}`);
res.setHeader('Set-Cookie',arr);
}
req.getCookie = function(key,options = {}){
let obj = querystring.parse(req.headers.cookie,'; '); // a=b; c=d; www=xxx a=b&c=d
return obj[key];
}
if(req.url === '/write'){
// 服务端不能跨域设置cookie 但是可以给子域设置
// domain 限制某个域下可以访问
// path 在哪个路径下可以访问cookie,以path开头的都能访问到,一般不设置
// expires、max-age 过期时间(秒) 如果做一些电商网站(如果用户一直访问这个页面,是不会退出登录的,所以每次操作的时候会把过期时间延长) 续命
// HttpOnly 只能服务器操作 默认false,如果改成true 客户端就不能操作cookie

// 客户端能篡改cookie 仿造请求
res.setHeader('Set-Cookie','name=jf; domain=.test.cn; path=/; max-age=10');

// 设置多个cookie,这里将line33注释,封装方法设置多个cookie 如下:
res.setCookie('name','jf',{domain: '.test.cn'});
res.setCookie('age','18',{httpOnly:true});
res.end('write ok');
return;
}
if(req.url === '/read'){
// res.end(req.headers.cookie || '空'); // 注释,用下面的方法获取设置的多个cookie的值
res.end(req.getCookie('name') || '空');
}
}).listen(3000);
// 执行 nodemon cookie.js

拓展

新加一个功能 算下用户访问的次数 visit

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
const http = require('http');
const querystring = require('querystring');
const sign = (value)=>{
// + / = 浏览器不支持
return require('crypto').createHmac('sha256','jf').update(value).digest('base64').replace(/\/|\+|\=/g,'');
}
http.createServer((req,res)=>{
let arr = [];
res.setCookie = function(key,value,options={}){
let opts = [];
if(options.domain){
opts.push(`domain=${options.domain}`)
}
if(options.maxAge){
opts.push(`max-age=${options.maxAge}`)
}
if(options.httpOnly){
opts.push(`httpOnly=${options.httpOnly}`)
}
// 有signed value + 加密代码(当value被客户端篡改时,用加密的代码做判断)
if(options.signed){ // 加盐算法
value = value + '.' + sign(value)
}
arr.push(`${key}=${value}; ${opts.join('; ')}`);
res.setHeader('Set-Cookie',arr);
}
req.getCookie = function(key,options = {}){
let obj = querystring.parse(req.headers.cookie,'; '); // a=b; c=d; www=xxx a=b&c=d
if(options.signed){
let [value,s] = obj[key].split('.');
let newSign = sign(value);
if(s === newSign){ // 判断用户是否改过
return value;
}else{
return undefined;
}
}
return obj[key];
}
if(req.url === '/write'){
res.setCookie('name','jf',{domain: '.test.cn'});
res.setCookie('age','18',{httpOnly:true});
res.end('write ok');
return;
}
// 新加一个功能 算下用户访问的次数 visit
if(req.url == '/visit'){
// signed:true 表示 签名 不被用户所篡改
let visit = req.getCookie('visit',{signed:true});
if(visit){
visit = visit-0+1;
res.setCookie('visit',visit+'',{httpOnly:false,signed:true});
}else{
visit = 1
res.setCookie('visit','1',{httpOnly:true,signed:true});
}
res.end(`当前第${visit}次访问`)
}

if(req.url === '/read'){
res.end(req.getCookie('name') || '空');
}
}).listen(3000);

session

新建session.js

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const http = require('http');
const uuid = require('uuid');
const querystring = require('querystring');

let session = {};
// 这里存储的是session的初始值,缺陷是存到内存中了,服务器挂了,这个对象里面的数据会丢失,如果放到数据库中,数据库挂了,信息也会丢失,问题就是 持久化丢了

let cardName = 'no.123456789';
http.createServer((req,res)=>{
let arr = [];
res.setCookie = function(key,value,options={}){
let opts = [];
if(options.domain){
opts.push(`domain=${options.domain}`)
}
if(options.maxAge){
opts.push(`max-age=${options.maxAge}`)
}
if(options.httpOnly){
opts.push(`httpOnly=${options.httpOnly}`)
}
// 有signed
if(options.signed){ // 加盐算法
value = value + '.' + sign(value)
}
arr.push(`${key}=${value}; ${opts.join('; ')}`);
res.setHeader('Set-Cookie',arr);
}
req.getCookie = function(key,options = {}){
let obj = querystring.parse(req.headers.cookie,'; '); // a=b; c=d; www=xxx a=b&c=d
if(options.signed){
let [value,s] = obj[key].split('.');
let newSign = sign(value);
if(s === newSign){ // 判断用户是否改过
return value;
}else{
return undefined;
}
}
return obj[key];
}
// 将cookie里面写的2个方法复制过来 setCookie、getCookie
if(req.url === '/wash'){
let id = req.getCookie(cardName)
if(id && session[id]){ // 有卡
session[id].money -=100;
res.end('current money is # '+session[id].mny)
}else{
let cardId = uuid.v4();
session[cardId] = {money:500};
res.setCookie(cardName,cardId);
res.end('current money is # 500 ')
}
}
res.end('Not Found');
}).listen(3000);

// 模拟场景 去理发店办卡,服务器给客户端一个唯一的cardId, 客户端通过cookie得到cardID,去服务端获取卡上的信息,服务端进行余额减少操作

后序会讲 jwt json web token (基于cookie的原理)

拓展

localStroage sessionStorage cookie session 区别

  • localStroage 不能跨域 最多能存 5M 超过丢失 发请求的时候不会自动带上
  • sessionStorage 浏览器关闭丢失
  • cookie 在header上 每次请求自动带上 解决http无状态的问题 header中不能存太多,最多4k 太多了也会浪费流量
  • session 基于cookie 存到服务器上

前后端分离 cookie 不支持,前后端分离基本上都是用token