Cookie 和 Session 是什么关系?

今天网络面试,碰到一道题

Cookie 和 Session 是什么关系?如何实现一个用户七天免登录的功能?

?????看到这道题的时候,我满脸黑人问号。我是面的前端还是后端?而且当时我也没答的很完整,因为我认为这里可能存在歧义,奈何我面试表现也一直不佳。(这难道就是我找不到好工作的原因吗?)

这道题看起来很简单,但是我相信很多前端程序员摸不着头。因为目前国内大多数文章并没有讲清楚 Session 是什么,对于前端程序员来说,Cookie 还是见过的,Session 又是什么东西?对于后端程序员来说,貌似两者就是同一个东西。

要解释这个东西,先从 http 说起。

我们都知道,http 是一种无状态的网络协议,无状态意味着每一个请求都与上下文无关。但是真实的网络请求的过程中,还是需要维持用户状态的,于是 Cookie 就出现了,服务器可以通过在请求头中设置Set-Cookie,在支持 Cookie 的浏览器上设置 Cookie(现在好像也没有浏览器不支持 Cookie 了吧),前端也可以通过浏览器 API 设置 Cookie。

Cookie 是浏览器利用 http 的 headers 实现的一种解决 http 无状态的方案。

前端眼中的 Session

Session 对前端来说很陌生,相信大家在网上也找过 Session 的资料,见过如下这些解释

该 Session 对象表示用户在当前浏览会话中已关闭的选项卡或窗口。

cookie 保存在客户端,session 保存在服务器端

第一个解释其实是浏览器的 API,相信很多前端都在 MDN 上看到这个解释,误以为这就是 Session。

第二个解释也是我们在国内能看到最多的对 Cookie 和 Session 的解释,但这也并没有解释为什么放在浏览器端是 Cookie,放在服务器的是 Session。也没说明 Session 和 Cookie 之间的关系呀。

可能更多的前端眼中的 Cookie 是这样子的,调用用户登录,API 验证帐号密码正确后,就会通过响应Set-Cookie种一个 Cookie 在浏览器上,之后请求只要携带这个 Cookie,后端就会返回想要的结果。Cookie 可以设置有效期,如果用户退出,删掉本地的 cookie 就能行,但是不明白为什么后端偏偏要给一个叫做安全退出的接口,可能还设置了 httponly 不允许前端通过 js 操作 Cookie。

抛开XSS攻击,把httponly去掉,来看看不使用安全退出接口,直接删除 Cookie,这种方式的退出会出现什么问题。

从前端看,只要删掉 Cookie,用户就退出了呀,有什么问题。其实这只是前端的退出,用户的登录状态其实在服务器上还是登录中。如果不通过接口通知服务器,服务器会一直以为用户依然在线,直至状态过期。

还是用登录来说明,用户登录这个过程中,后端都做了什么?

前端把用户的帐号密码甚至还可能有验证码发送给后端,后端查数据库后确认用户的帐号密码甚至是验证码都是正确的,使用一些手段给该用户生成一个唯一的 id,存在数据库中,这个数据库可以是任何一种数据库,这里我们假设使用的是 Redis。同时从 mysql 或者 mongodb 中把可能常用到的数据作为 value 与唯一 id 存在 Redis 中。然后把这个 id 通过Set-Cookie或者 body 或者 url 甚至是其他的方式通过响应返回给客户端。

在这里,那个唯一 id 可以称之为 Session id(但是为什么叫做 Session,据说是和 servlet 有关,我是没写过那玩意儿,有待考古,就姑且称为 Session 好了),如果使用的是 OAuth2.0,或许叫做 token,或者和前端一样叫 Cookie 也没毛病,毕竟如果通过设置Set-Cookie,那这个 id 就是浏览器上的 Cookie。如果没有Set-Cookiehttponly,是通过 body 或者其他方式响应给前端,前端甚至可以自己设置 Cookie,放在 localStorage 也是没问题的。只要下次请求按照前后端规定的格式带上,就能拿到想要的数据了。

说了这么多,Session 和 Cookie 到底是什么?其实这个问题问的就有歧义。

在后端,可以把用户登录直到退出这段过程成为 Session,识别这次 Session 的 id 成为 Session id,把 Session id 通过Set-Cookie的方式种在浏览器中,以此来共同维护用户的状态。如果后端使用的是 OAuth2.0,那可能称之为 token。如果前端能从操作这个识别 id,把 id 设置到 localStorage,而不是 Cookie,只要遵循规定好的格式,一样能识别用户。

如何实现一个用户七天免登录的功能?

这个问题,解答其实可以很简单。通过Set-Cookiehttponly给浏览器种一个有效时间为七天的的 Cookie。并且在 Redis 中利用 ttl 设置一个有效期为七天的 Session id(或者 token),就能实现用户七天免登录的功能。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!