无状态http我们都知道http请求和响应是相互独立的,服务器无法识别两次http请求是否是同一个用户发出的。也就是说,服务器不具备记录通信状态的能力。我们通常使用cookie和session来确定会话中双方的身份。cookiecookie是服务器端发送过来的,服务器端给不同的用户发送不同的标识。该标识符表示用户的身份。服务器端通过客户端发送的标识识别用户的身份,从而在服务器端查询用户的相关数据。然后发送给该用户。安装express提供的cookie-parser中间件:npmi-Scookie-parser在我们使用的项目页面模块中引入cookie-parser插件,然后实例化,如下:varcookieParser=require('cookie-parser');varcp=cookieParser(秘密,选项);它有两个参数,第一个参数是secret,可以用来对cookie进行签名,也就是我们常说的cookie加密。它可以是字符串或数组。熟悉加密原理的同学应该知道,这个字符串就是服务器拥有的密文。第二个参数options包括以下可选参数:path:指定受cookie影响的路径expires:指定时间格式maxAge:指定cookie何时过期secure:secure值为true时,在HTTPS中有效;否则,cookie在HTTP中是有效的。httpOnly:浏览器不允许脚本操作document.cookie来改变cookies。将其设置为true以避免从xss攻击中获取cookie。参考cookie-parser中的例子,实现一个记住访问路径的demo。代码如下:varpath=require('path');varexpress=require('express');varcookieParser=require('cookie-parser');varapp=express();//使用cookieParser中间件;app.use(cookieParser());//如果请求中的cookie存在isFirst//否则设置cookie字段为First,并设置过期时间为10秒app.get('/',function(req,res){if(req.cookies.isFirst){res.send("欢迎再次光临");console.log(req.cookies)}else{res.cookie('isFirst',1,{maxAge:60*1000});res.send("Welcometothefirstvisit");}});app.listen(3030,function(){console.log('expressstarton:'+3030)});cookie-parser还可以对cookie数据进行加密,也就是我们所说的signedCookies。signedCookies的实现代码如下:varpath=require('path');varexpress=require('express');varcookieParser=require('cookie-parser');varapp=express();//使用cookieParsermiddleware;app.use(cookieParser('my_cookie_secret'));//cookieapp.get('/',function(req,res){if(req.signedCookies.isFirst){res.send("欢迎再次访问");console.log(req.signedCookies)}else{res.cookie('isFirst',1,{maxAge:60*1000,signed:true});res.send("欢迎初次访问");}});从上面的代码我们知道cooke-parser的第一个参数可以指定服务端提供的加密密钥,然后我们就可以使用options中的signed配置项来实现加密。虽然这样比较安全,但是客户端的Cookie有局限性。客户端发送请求时,会增加请求头中的数据量,导致请求速度变慢;此外,它不能实现数据共享。sessionexpress-session是expressjs创建会话的中间件。服务端生成session-id,客户端使用cookie保存session-id加密后的请求信息,将用户请求的数据保存在服务端,但也可以将用户的数据加密保存在客户端。会话记录了客户端与服务器之间的会话状态,用于判断客户端的身份。express-session支持session存储位置可以存储在cookie中,也可以存储在内存中,也可以存储在redis、mongodb等第三方服务器中。session默认存储在内存中,存储在cookie中安全性太低,存储在非redis数据库中查询速度太慢。一般在项目开发中存储在redis(缓存数据库)中。express提供的express-session中间件安装命令:npmi-Sexpress-session在我们使用的项目页面模块中引入express-session插件,然后实例化,如下:varsession=require('express-session');varse=session(选项);session()的参数options配置项主要包括:name:设置cookie中保存的session的字段名,默认为connect.sidstore:session的存储方式,默认存储在内存中,我们可以自定义redis等genids:在生成新的session_id时,默认使用npm包uid2。rolling:每次请求都会重置一个cookie,默认为false。对于truesaveUninitialized:强制将未初始化的session保存到数据库secret:通过设置的secret字符串计算hash值,放入cookie中,使生成的signedCookie防篡改cookie:设置存储sessionidcookie的相关选项那么,使用它我们能做什么呢?下面我们一一介绍。cookiesessioncookiesession的使用非常简单,就是我们在配置项中使用cookie配置项,将session数据保存在cookie中。类似于signedCookies,都是在客户端保存数据,都是对数据进行加密,只是加密后的后续请求得到的数据结构不同。cookesession的结构如下:Session{cookie:{path:'/',_expires:2018-01-29T17:58:49.950Z,originalMaxAge:60000,httpOnly:true},isFirst:1}signedCookie结构如下:{isFirst:'1'}cookiesession代码如下:varpath=require('path');varexpress=require('express');varsession=require('express-session');varredisStore=require('connect-redis')(session);varapp=express();//sessionapp.use(session({name:'session-name',//这里是cookie的名字,默认是connect.sidsecret:'my_session_secret',//推荐128个字符的随机字符串resave:true,saveUninitialized:false,cookie:{maxAge:60*1000,httpOnly:true}}));//routeapp.get('/',function(req,res,next){if(req.session.isFirst||req.cookies.isFirst){res.send("欢迎再次访问");}else{req.session.isFirst=1;res.cookie('isFirst',1,{maxAge:60*1000,singed:true});res.send("欢迎第一次访问。");}});app.listen(3030,function(){console.log('expressstarton:'+3030)});signed-cookievscookiesessionsignedCookies信息可见但不可修改,而cookiesession是不可见的UnmodifiablesignedCookies信息长期保存在客户端,后面客户端关闭,信息消失。对于Cookesession,增加了客户端请求的数据大小,我们一般这样使用,而databasestoresthesession数据库保存session数据库保存session,我们一般用redis,因为是缓存数据库,查询速度比非缓存快,express-session的示例代码是如下:varpath=require('path');varexpress=require('express');varsession=require('express-session');varredisStore=require('connect-redis')(session);varapp=express();//sessionapp.use(session({name:'session-name',//这里是cookie的名字,默认是connect.sidsecret:'my_session_secret',//就是建议使用128个字符的随机字符串resave:true,saveUninitialized:false,store:newredisStore({host:'127.0.0.1',port:'6379',db:0,pass:'',})}));//routeapp.get('/',function(req,res){if(req.session.isFirst){res.send("欢迎再次访问。");console.log(req.session)}else{req.session.isFirst=1;res.send("欢迎初次访问。");}});app.listen(3030,function(){console.log('expressstarton:'+3030)});但是有时候我们也会使用非redis的数据库来保存session,这时候就需要对项目结构有很深的认识和理解,否则的话,使用后会适得其反,另外要注意使用数据库保存session数据,浏览器端的session-id会随着浏览器的关闭而消失,下次打开浏览器发送请求时,服务器仍然无法识别请求者。cookiesession虽然解决了这个问题,但是它本身也存在安全隐患。实际上cookiesession和signedCookies都面临xss攻击。实际上signedCookies和session的结合会降低这种风险signedCookies(cookies)与session的结合发展起来,其中,我们往往需要signedCookies的长期保存特性和session的不可见不可修改特性。varpath=require('path');varexpress=require('express');varcookieParser=require('cookie-parser');varsession=require('express-session');varredisStore=require('connect-redis')(session);varapp=express();//使用cookieParser中间件;app.use(cookieParser());//sessionapp.use(session({name:'session-name',//这里是cookie的名字,默认是connect.sidsecret:'my_session_secret',//建议使用128个字符的随机字符串resave:true,saveUninitialized:false,//cookie:{maxAge:60*1000,httpOnly:true},store:newredisStore({host:'127.0.0.1',port:'6379',db:0,pass:'',})}));app.get('/',function(req,res,next){if(req.session.isFirst||req.cookies.isFirst){res.send("欢迎再次访问");}else{req.session.isFirst=1;res.cookie('isFirst',1,{maxAge:60*1000,singed:true});res.send("欢迎初次访问。");}});app.listen(3030,function(){console.log('expressstarton:'+3030)});这样我们就把session信息保存在redis中,用session_id标记客户端cookie的一份副本,所以我们不用担心浏览器关闭后cookie中的session_id字段会消失的情况,因为浏览器还有它的备份cookie,如果没有备份cookie信息,下次客户端如果客户端再次发送请求浏览,则无法判断用户身份,参考源码nodejs快速上手
