掘金 后端 ( ) • 2024-04-29 13:54

最近作者在学习nest框架,在前端验证码实战中遇到了一些问题。为什么服务器端设置的session会保存到浏览器的cookie里?服务器端又是否会保存session数据呢?在经过大量的资料查询后,就有了这篇文章: 作者旨在用通俗易懂的语言,讲清楚什么是服务器session、浏览器的sesisonStorage和Cookies

服务器Session

简单来说,Session是服务器端存储数据的一种方式。

首先我们要区分Session和SessionStorage,这两个概念在作者初学时经常搞混,在这里我们只需要记住一句话:

Session里的数据存储到服务器端,SessionStorage里的数据存储到用户本地浏览器

如果你和作者一样,是学前端的,那么你可能会产生和作者一样的感叹:原来服务器端也能保存数据啊!在很长一段时间里,作者都以为服务器端的数据都会通过HTTP协议,存储到本地浏览器里。当时还在想,在做前端登录验证码的时候,如果在浏览器储存中找到验证码图片对应的值直接填进去,不就可以绕过验证码?

常见的登录验证码图片:

image.png

事实证明还是作者太年轻。

为什么需要Session?

回到文章,既然Session的数据存在服务器端,那为什么需要Session呢?如果要做验证码的话,需要有个地方保存验证码图片对应的值,即文本"9HZ1" ,然后前端收集到用户输入的验证码后做验证。如果这个文本值存在浏览器本地的话,那就非常容易绕过去,只需要找到存储的地方,找到对应的值就好了。

所以为了安全性,服务器端需要能够存储数据的地方,这个地方就是Session

那么除了这个用途外呢?Session还可以用来做什么呢?在深入了解这个问题前,我们先来看看Session的存储格式:

Session存储格式

Session里的数据是通过键值对的形式储存的,你可以将Session看作许多个小格子,每一个小格子都可以存储独立的数据。每一个小格子都有需要设置一个独一无二的ID,即session_id,用来标识数据,通常这个session_id是随机生成的,你也可以自定义。我们可以用一个小格子,对应一个登陆的用户:

{
  "session_id": "独一无二的ID,用来标识Session",
  //存入用户id
  "user_id": 42,
  //如果用户没有登录,则为false
  "is_authenticated": true,
  //假设我们做的是电商平台,这里可以存入用户购物车的数据
  "shopping_cart": [
    {"item_id": 101, "quantity": 2},
    {"item_id": 205, "quantity": 1}
  ]
}

不知道你有没有注意到,我们在Session里面存入了用户的数据,其中有一点就是用户是否登录。要知道HTTP协议是无状态的,用户登陆前发送的Post请求和登陆后发送的Post请求没有区别。

那我们如何分辨,哪些请求是登陆前发送的,哪些请求是登陆后发送的呢?我们就可以用Sessioin来解决,通过在Session中保存用户登录状态,然后收到用户Post请求后,查询服务器本地的Session,找到用户id为42对应的Session,然后查看登陆状态是否为真。

这样我们就区分出了登录用户和未登录用户。

如何在服务器端找到当前用户对应的Session?

我们之前提到,在服务器端储存Session的每一个小格子,都有一个独一无二的session_id作为唯一标识,所以我们可以用这个session_id去找到当前用户对应的Session储存。但是这就衍生出了一个问题: 既然HTTP协议是无状态的,那我怎么知道当前Post请求就是之前那个用户发出的呢?就算我知道了当前用户就是之前登陆的用户,我又如何获取用户对应的session_id呢?

我们可以用Cookies解决这个问题:

解决思路与之前相似,既然HTTP协议是无状态的,我们把状态存储下来就好。既然不知道如何获取用户对应的session_id,那么在用户登陆后,将用户对应的session_id存储到浏览器本地,然后每次发送请求时,前端都把这个session_id携带上去,然后后端不就知道当前的请求是哪个用户发出的了吗。

后端通过前端携带的session_id,找到了服务器上存储的与用户相关的数据后,不久找到了之前用户的状态了吗?妙啊妙啊