Express session应用与原理源码解析

  • 什么是session
  • Express session实例应用
  • Express session源码解析

 一、什么是session

1. 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
2. 思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。(url重写可以参考:https://www.cnblogs.com/ttjava/p/3641014.html
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
(以上内容来源:https://www.zhihu.com/question/19786827/answer/28752144)

 二、Express session实例应用(登入验证)

 1.构建项目结构
npm init -y
npm install express -save-dev
npm install cookie-parser -save-dev
npm install express-session -save-dev
npm install body-parser -save-dev
npm install ejs -save-dev

//项目结构
express_session
    page
        login.html
        home.html
    index.js
    node_modules
    package.json
    package-lock.json

这个实例主要解析node后台的express-session的应用,就不采用前端的数据渲染框架,而是采用后端模板渲染框架ejs。ejs官方文档:https://ejs.bootcss.com/

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>登入页面</title>
 6 </head>
 7 <body>
 8 <form action="/login" method="POST">
 9     账号:<input type="text" name="userid" />
10     密码:<input type="password" name="userpassword"/>
11     <input type="submit" value="登入">
12 </form>
13 </body>
14 </html>
login.html
 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>首页</title>
 6 </head>
 7 <body>
 8     <p id="use">用户:<%= username %> | 账号:<%= userid %></p>
 9     <p><a href="/logout">退出</a></p>
10 </body>
11 </html>
home.html
 1 //后台核心代码
 2 const express = require('express');
 3 const cookieParser = require('cookie-parser');
 4 const session = require('express-session');
 5 const bodyParser = require('body-parser');
 6 const app = express();
 7 
 8 app.use(cookieParser());
 9 app.use(session({
10     cookie:{maxAge:1000*30},
11     secret:'leo'
12 }));
13 
14 app.set("view engine","html");//设置解析魔棒的文件类型
15 app.set("views",  __dirname+ "\page");//设置模板路径
16 app.engine('html',require('ejs').renderFile);//指定ejs引擎解析渲染模板路径下的html文件
17 
18 app.use(bodyParser.json());
19 app.use(bodyParser.urlencoded({extended: true}));
20 
21 
22 //获取登入页面
23 app.get('/login',function(req,res){
24     res.sendFile(__dirname + '/page/login.html');
25 });
26 
27 //用户登入(登入账号验证)
28 app.post('/login',function(req,res){
29     if(req.body.userid === '12300001111' && req.body.userpassword === '123456'){
30         req.session.userid = req.body.userid; //登入成功,设置session
31         req.session.username = '他乡踏雪';     //...
32         res.redirect('/home');
33     }else{
34         res.json({ret_code:1,ret_msg:'账号密码错误'});
35     }
36 });
37 
38 //获取主页(响应首页前通过session验证用户是否登入)
39 app.get('/home',function(req,res){
40     if(req.session.userid){
41         res.render('home',{
42             username:req.session.username,
43             userid:req.session.userid
44         });
45     }else{
46         res.redirect('/login');
47     }
48 });
49 
50 //退出
51 app.get('/logout',function(req,res){
52     req.session.username = null;
53     req.session.userid = null;
54    res.redirect('/login');
55 });
56 
57 app.listen(12306);

 三、Express session原理及源码解析

 3.1基于cookie的session:

从某种意义上来说,session就是服务端的cookie,而且session是基于cookie的,就会受到浏览器的用户禁用cookie的限制,在IE8时期可以通过HTML5的storage来填补这一空缺,因为在即便是浏览器禁用了cookie也仅仅只是不能在本地存储cookie,服务的session如果根据IP和一系列数据签名匹配到相关session,然后响应头还是会携带cookie,所以就可以通过js解析cookie然后在本地使用storage来替代cookie,这是本地禁用cookie的解决方案。

同样在服务端由于session默认存储再内存中,如果服务停止或重启内存的数据就会被清除,所以再服务端也是有必要对session做持久化的,这些在session上针对不同的session都由丰富的插件模块,下面这份代码是在第一部分基础上实现了session文本存储持久化,使用的是:session-file-store(官方文档:https://www.npmjs.com/package/session-file-store),详细见代码。

 1 const express = require('express');
 2 const cookieParser = require('cookie-parser');
 3 const session = require('express-session');
 4 const bodyParser = require('body-parser');
 5 //session-file-store官方文档:https://www.npmjs.com/package/session-file-store
 6 //express-session官方文档(更多session存储模式可以参考这个):https://github.com/expressjs/session
 7 const FileStore = require('session-file-store')(session);//引入session本地文件存储模块
 8 const fileStoreOptions = {};//配置session本地存储模块的相关参数,空对象表示默认参数,详细参考
 9 const app = express();
10 
11 
12 
13 app.use(cookieParser());
14 app.use(session({
15     store: new FileStore(fileStoreOptions),//启动session本地文件存储
16     cookie:{maxAge:1000*30},
17     secret:'leo'
18 }));
19 
20 app.set("view engine","html");//设置解析魔棒的文件类型
21 app.set("views",  __dirname+ "\page");//设置模板路径
22 app.engine('html',require('ejs').renderFile);//指定ejs引擎解析渲染模板路径下的html文件
23 
24 app.use(bodyParser.json());
25 app.use(bodyParser.urlencoded({extended: true}));
26 
27 
28 //获取登入页面
29 app.get('/login',function(req,res){
30     res.sendFile(__dirname + '/page/login.html');
31 });
32 
33 //用户登入(登入账号验证)
34 app.post('/login',function(req,res){
35     if(req.body.userid === '12300001111' && req.body.userpassword === '123456'){
36         req.session.userid = req.body.userid; //登入成功,设置session
37         req.session.username = '他乡踏雪';     //...
38         res.redirect('/home');
39     }else{
40         res.json({ret_code:1,ret_msg:'账号密码错误'});
41     }
42 });
43 
44 //获取主页(响应首页前通过session验证用户是否登入)
45 app.get('/home',function(req,res){
46     if(req.session.userid){
47         res.render('home',{
48             username:req.session.username,
49             userid:req.session.userid
50         });
51     }else{
52         res.redirect('/login');
53     }
54 });
55 
56 //退出
57 app.get('/logout',function(req,res){
58     req.session.username = null;
59     req.session.userid = null;
60     res.redirect('/login');
61 });
62 
63 app.listen(12306);
View Code

更多session持久化可以参考session的官方文档:https://github.com/expressjs/session,比较常见的MongoDB、Redis。

 2.session源码浅析:

这一部分主要参考这篇博客:https://blog.csdn.net/weixin_33824363/article/details/91393870

session源码只有四个模块,分别是:cookie.js、memory.js、session.js、store.js再加一个入口模块index.js。

cookie:用来配置cookie相关的参数。

store:用来实现session数据持久化操作的模块。

session:主程序模块。

memory:用来实现数据缓存,也就是session默认情况下存储在内存中的操作。

index:入口模块。

原文地址:https://www.cnblogs.com/ZheOneAndOnly/p/13130336.html