使用过几种Web App开发语言和框架,都会接触到Session的概念。即便是一个简单站点访问计数的功能,也经常使用Session来实现的。其余经常使用的领域还有购物车,登陆用户等。可是,对Session一直是只知其一;不知其二,知其然而不知其因此然。php
在认真的研究了HTTP协议,以及nodejs开发栈的express和express-session后,我终于比较有把握深刻浅出的说清楚Session了,也算是知足了多年来开发过程当中,经常浮现的对Session的好奇心吧。node
本文使用nodejs v9.5.0做为技术验证工具。阅读本文前须要了解基础的HTTP知识和Cookie知识。详细须要参考rfc6265,或者阅读《HTTP小书》的最后一章。mysql
用户在网站的一组相互关联的的请求和响应,就是一次会话。简而言之是这样的:redis
好比一个最简单的nodejs HTTP程序:算法
var http = require('http') http.createServer(function(req,res){ res.end('hello') }).listen(3000)
每一个请求都会进入到此处理函数:function(req,res){res.end('hello') }
,在此函数内得到请求,处理响应,完成后发给客户端,就是一次访问。经过浏览器的developer tools,能够看到这次会话的请求内容和响应内容。sql
以站点计数应用为案例来讲明的话,就是这些来自于一样访问者的屡次访问,均可以得到当前站点的访问计数。mongodb
咱们从一个案例开始引入会话的概念。当咱们须要访问站点计数一类的功能时,咱们但愿用户访问此站点时:chrome
此种状况下,咱们须要有一个地方存储当前计数,这样才能在同一个客户在此访问时,能够取出当前计数,加一后返回给客户。固然也所以须要识别此用户(浏览器),为每一个用户单独计数。就是说,不一样的用户访问时,须要去取对应用户的当前计数。数据库
识别客户的问题,经常使用的方法就是使用Cookie。Cookie是HTTP协议的一部分。HTTP能够经过头字段Set-Cookie为来访客户作一个标记,这个标记经常就是一个ID,下一次访问此站点时,HTTP会经过Cookie头字段,发送此ID到站点,由此站点知道此客户的身份和这个身份关联的状态信息,好比当前访问计数,或者此身份当前的购物车的内容等等。express
识别了客户后,就能够在Web服务器内,为此客户创建它的独特的状态信息。
基于nodejs HTTP模块,咱们实现一个极为简单的Session服务。只是为了展现概念,而不是为了实用的目的。此服务能够实现一个共享于同一站点的屡次访问的req.session变量,此变量为一个对象,能够在此变量内写入新的成员,或者修改现存的成员变量的值,每次访问后会保存req.session,以便下次访问能够获得当前的值:
var http = require('http') var sessionkey = "sessionkey3" http.createServer(function(req,res){ if (req.url =="/"){ session(req,res) req.session.count = (req.session.count+1) || 1 res.end('hi'+req.session.count) }else res.end('') }).listen(3000) console.log('listen on 3000') function session(req,res){ if (req.session) return var answer ,id if(isSessionOk(req)){ id = getCookie(req) answer = getSessionById(id) }else{ answer= {} id = createSession(answer) setCookie(res,id) } req.session = answer res.on('finish', function() { saveSession(id,req.session) }); } function hasCookie(req){ return (getCookie(req)!='') } function getCookie(req){ try{ var c = req.headers['cookie'] var arr = c.split(';') for (var i = 0; i < arr.length; i++) { var kv = arr[i] var a = kv.split('=') if (a[0].trim() == sessionkey) return a[1] } }catch(error){ return '' } return '' } function setCookie(res,id){ res.setHeader("set-cookie",sessionkey +"="+id) } var sessions = {} var sid = 0 function getSessionById(sid){ return sessions[sid] } function getSessionByReq(req){ var sid = getCookie(req) return sessions[sid] } function createSession(session){ sessions[sid++,session] return sid } function saveSession(sid,session){ sessions[sid] = session } function isSessionOk(req){ return hasCookie(req) && getSessionByReq(req) !== undefined }
程序代码比较简单,读者能够保持它到index.js,而后执行此程序,验证概念:
node index.js
而后,启动chrome,访问站点localhost:3000
,而后屡次刷新,你能够看到每次刷新,返回的访问次数逐步累加。在打开另外一个浏览器,好比safari,在此访问此站点,你会发现返回的访问计数从1开始,另外计数。由于是两个不一样的浏览器内器,这就保证的它们是不一样的访问客户,在站点内的代码,会区别二者,分别记录它们的状态信息。
代码使用了HTTP Cookie,基本算法很简单:
可能你们看到sessionkey这个变量,感受有些莫名其妙。缘由是每次cookie发送,一样的站点可能有多个框架须要使用此cookie头字段,好比php,aspx,jsp等都是须要使用了,为了好像不要冲突,你们各自使用cookie头字段内各自的key/value对便可。好比php的key默认是phpsessid,express-session默认的是connect.sid。
此代码演示了最基础的Session的概念,可是远远不是一个可用的模块,想要真实世界中使用的Session模块,能够考虑express-session。
实现一个真正能够的会话,还须要考虑不少问题:
更多的考量,能够去经过阅读express-session来得到。本文阅读完毕,自己就是能够成为阅读express-session的基础材料的。