cookie和session:状态来了
做web开发,就离不开cookie和session,这一切要从HTTP协议开始说起。
HTTP:没有状态
HTTP最初是一个无状态
的协议,服务器响应客户端的请求,然后向客户端返回一条响应。Web服务器无法判断是哪个用户发送的请求。在现实的网站应用中,服务端希望能够对客户端的用户有更多的了解,能在用户浏览页面时对其进行追踪。比如,常见的电子商务网站,希望能够个性化的推荐客户感兴趣的商品,如果不能识别另一端的用户,那么这个目的就无法达到。
cookie:我在客户端
为了实现这一目标,人们探索了很多方式,虽然有其他的一些方式可以达到识别用户的目的,但毫无疑问,cookie是应用最广泛,也最方便的一种。
那cookie到底是什么呢?你可以理解为它是一个“标记
”,当用户首次请求服务器时,服务器通过设置响应头中的set-cookie
属性来通知浏览器将cookie存起来。之后,浏览器每次请求服务器时,都会将cookie传递给服务器,因为每个用户的cookie都不一样,通过这种的方式,服务器就能正确识别每个用户了。
session:我在服务端
我们已经知道,cookie是一个存储在客户端的“标记”,既然已经有了cookie,为啥又搞出来一个session?
那我问你,既然客户端已经将cookie存了起来,那么服务端是不是也需要存储一个相对应的“标记”信息,不然,当客户端返回cookie时,服务端怎么知道这个cookie对应之前的哪个用户?
这个相对应的“标记”信息就是session,它存储在服务端。
动手实践
说了这么多,可能还是不太明白,没关系。接下来,我们将抽象概念具体化,亲自动手做一做,来观察这个所谓的cookie和session到底长什么样,它们之间又是如何关联的。
我这里用Node.js来进行说明,先安装相关库:
npm i express express-session -S
express是一个web开发框架,express-session是一个中间件。为了方便说明,我精心准备了一个非常简单的小例子:
const express = require('express')
const session = require('express-session')
const HOUR = 1000 * 60 * 60
const secret = Math.random().toString()
const app = express()
app.use(
session({
key: 'node_session_id',
secret,
cookie: { maxAge: HOUR * 8, secure: false },
resave: true, // Forces the session to be saved back to the session store
saveUninitialized: true,
rolling: true // Force the session identifier cookie to be set on every response.(browser)
})
)
app.use(function (req, res, next) {
if (req.url === '/favicon.ico') {
return
}
const sess = req.session
const id = req.sessionID // session ID, 只读
console.log(sess, id)
if (sess.views) {
sess.views++
} else {
sess.views = 1
}
res.header('Content-Type', 'text/html')
res.write('<p>views: ' + sess.views + '</p>')
res.write('<p>expires in: ' + sess.cookie.maxAge / 1000 + 's</p>')
res.write('<p>httpOnly: ' + sess.cookie.httpOnly + '</p>')
res.end()
})
app.listen(8000)
上面代码实现了一个简单的页面浏览计数功能。运行上面代码,打开浏览器,刷新页面,观察控制台中打印的sess和id的值:
我们发现,Session是一个对象,其中包含了cookie
和views
变量。每个Session都有一个唯一的sessionID,就是上面的id变量。
那么cookie又是怎样的呢?
我们打开浏览器开发工具,以chrome为例,在Application
页面的Cookies
中就能观察到上面这个cookie:
它有一些属性,比如Name,Value,Path等,我们这里重点关注它的值:
s%3AWHfaTE0ReCvZ87MbgqCYyyh4mEzBXtg_.jsAPINUgoB21qOQocWK1S9bzFHDnGP1mvA%2FHCU9miJQ
这个值其实分为两部分(用点号分割),前面一部分为 WHfaTE0ReCvZ87MbgqCYyyh4mEzBXtg_
,正是服务端那个SessionID的值。客户端的cookie和服务端的session正是通过这个值来一一对应。
在同一浏览器中刷新页面,控制台上打印的始终是同一个session,只不过其中的views的值变了,也就是说,多次http连接对应的是同一个会话。