http是无状态的
但是服务器可以通过session来保存状态
一般是在web应用的背景之下,我们知道web应用是基于HTTP协议的,而HTTP协议恰恰是一种无状态协议。也就是说,用户从A页面跳转到B页面会重新发送一次HTTP请求,而服务端在返回响应的时候是无法获知该用户在请求B页面之前做了什么的。
对于HTTP的无状态性的原因,相关RFC里并没有解释,但联系到HTTP的历史以及应用场景,我们可以推测出一些理由:
总而言之,HTTP的无状态是由其历史使命而决定的。但随着网络技术的蓬勃发展,人们再也不满足于死板乏味的静态HTML,他们希望web应用能动起来,于是客户端出现了脚本和DOM技术,HTML里增加了表单,而服务端出现了CGI等等动态技术。
而正是这种web动态化的需求,给HTTP协议提出了一个难题:一个无状态的协议怎样才能关联两次连续的请求呢?也就是说无状态的协议怎样才能满足有状态的需求呢?
此时有状态是必然趋势而协议的无状态性也是木已成舟,因此我们需要一些方案来解决这个矛盾,来保持HTTP连接状态,于是出现了cookie和session。
https://github.com/koajs/generic-session
需要区分
npm i -S mongoose bluebird
npm i -S koa-generic-session koa-generic-session-mongo
提示,当发现bcrypt无法安装的时候
> bcrypt@0.8.7 install ~/workspace/github/mongoose-base-user-plugin/node_modules/bcrypt
> node-gyp rebuild
gyp: ~/.node-gyp/4.4.5/common.gypi not found (cwd: ~/workspace/github/mongoose-base-user-plugin/node_modules/bcrypt) while reading includes of binding.gyp while trying to load binding.gyp
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack at ChildProcess.onCpExit (~/.nvm/versions/node/v4.4.5/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:343:16)
gyp ERR! stack at emitTwo (events.js:87:13)
gyp ERR! stack at ChildProcess.emit (events.js:172:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Darwin 14.5.0
gyp ERR! command "~/.nvm/versions/node/v4.4.5/bin/node" "~/.nvm/versions/node/v4.4.5/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd ~/workspace/github/mongoose-base-user-plugin/node_modules/bcrypt
gyp ERR! node -v v4.4.5
gyp ERR! node-gyp -v v1.0.3
gyp ERR! not ok
npm ERR! Darwin 14.5.0
npm ERR! argv "~/.nvm/versions/node/v4.4.5/bin/node" "~/.nvm/versions/node/v4.4.5/bin/npm" "i"
npm ERR! node v4.4.5
npm ERR! npm v2.10.1
npm ERR! code ELIFECYCLE
npm ERR! bcrypt@0.8.7 install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the bcrypt@0.8.7 install script 'node-gyp rebuild'.
npm ERR! This is most likely a problem with the bcrypt package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild
npm ERR! You can get their info via:
npm ERR! npm owner ls bcrypt
npm ERR! There is likely additional logging output above.
解决方案
rm -rf ~/.node_gyp
引用
const session = require('koa-generic-session')
const MongoStore = require('koa-generic-session-mongo')
核心代码
app.keys = ['keys', 'keykeys'];
app.use(session({
store: new MongoStore({
url: require('./mongodb').url(),
ttl: 6000
})
}));
这样是全局的使用session,在后面的中间件里可以使用ctx.session,如果想定制高效,可以在具体路由里使用该session中间件,而非全局。
比如注册
// 注册信息保存
router.post('/register', ctx => {
console.log(ctx.request.body)
var session = ctx.session
let body = ctx.request.body
let user = new User({
username: body.name,
password: body.password
})
return user.save(function(err, doc){
if (err) {
return ctx.redirect('/404')
}
session.current_user = {
username: body.name,
password: body.password
}
return ctx.redirect('/')
})
})
然后在其他中间件里即可,获取通过session来共享current_user对象,达到了状态保存的目的。
但session是有时效的,根据ttl设置自动销毁,比如tomcat的默认时间是30分钟,这个可以酌情设置。当session失效,就变成游客模式。
既然session是一个对象,可以挂无数东西,那么是不是什么都可以挂呢?session如果使用cookie存,是内存模式,如果东西太多,会内存爆掉,如果使用db存储(redis或mongodb),就没有这样的问题,但仍然会占用较多,所以。。。除非必要,尽量少在session上放东西。
以前的购物车是放到session里,但真正的电商购物车早已经不用session里,而是持久化。所以目前来看除了和用户登录相关的,很少会用到session。