Cookie VS Session VS Storage

101 阅读9分钟

1.静态服务器

收到请求后,不用对请求进行额外处理,直接读取文件内容并返回。主要提供静态资源,不同用户访问到的资源相同

对于每一次发过来的请求基本上都是同一个处理,所以我们可以不需要区分请求的文件路径,一个一个做处理,直接统一处理,具体差异化部分再细化(下面是nodejs服务端代码,简单实现,主要是便于理解)

let server = http.createServer(function (req, res) {
    let params = url.parse(req.url, true)
    let pathWithQuery = req.url
    console.log(params)
    let path = params.pathname
    let query = params.query
    console.log('有请求发送过来了!路径是' + pathWithQuery)

    if(path === '/'){
        path = '/index.html'
    }
    let suffix = path.substring(path.lastIndexOf('.')+1)
    let contentMap = {
        'html':'text/html',
        'js':'text/javascript',
        'css':'text/css',
        'json':'application/json',
        'xml':'text/xml',
        'png':'image/png',
        'jpg':'image/jpeg',
        'gif':'image/gif'
    }
    res.statusCode = 200
    
    res.setHeader('Content-Type', `${contentMap[suffix] || 'text/html' } ;charset=utf-8`)
    let content;
    try{
        content = fs.readFileSync(`public${path}`)
    }catch(error){
        res.statusCode = 404
        content = '文件不存在'
    }
    res.write(content)
    res.end()
})

server.listen(port)

2.动态服务器

收到请求后,需要对请求,需要进行一些处理,才文件内容返回。提供动态服务,不同用户访问到的资源不同

登陆注册网站为例

例子中涉及到用户登陆成功后,再去做其他操作时,由于HTTP是无状态的,所以不会记录这个用户已经登陆过,为了解决这个问题,引入了Cookies。将Cookies添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态

虽然HTTP无状态,但使用Cookies可以创建有状态的会话

3. Cookie

HTTP Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的HTTP 协议记录稳定的状态信息成为了可能。

创建Cookie

在用户登陆成功时,服务器使用Set-Cookie响应头部向浏览器下发Cookies

Set-Cookie: <cookie名>=<cookie值>

服务器通过该头部告知客户端保存Cookie信息

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

在这之后,该网站对该服务器发起的每一次新的请求,浏览器都会将之前保存的Cookie信息通过Cookie请求头部再发送给服务器

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

Cookie的生命周期

默认是浏览器关闭之后就会自动删除,仅在会话期内有效

也可以设置过期时间(Expires)或者有效期(Max-Age),指定保存时间

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

限制访问Cookie

标记为SecureCookie只允许通过HTTPS请求发送给服务端

Javascript可以通过document.cookie获取cookie,但是对于设置HttpOnly属性的Cookie,是无法被JavaScript访问到的

document.cookie也可以新建Cookie,但通过JavaScript创建的 Cookie 不能包含 HttpOnly 标志。

更多Cookie的详细内容,可以参考MDN

4. session

上面的例子中,起初是采用Cookie存储userId,后面改用session的方式

主要是在服务端新建一个文件(例子的是session.json),存储的数据是对象,对象的key是随机数(session_id),value是对应的userId,然后在用户登录时,将session_id通过Cookie发送给浏览器,浏览器端存储的就是一个随机数,对于外人看来是一个没啥具体意义的数字。

我们可以大概了解到,上述的session是借助了Cookie实现,但不是只有这一种实现方式,只是常用的一种方案

Session 代表着服务器和客户端一次会话的过程。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当客户端关闭会话,或者 Session 超时失效时会话结束。

Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;

Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

5. Cookie Session的区别

  • 作用范围不同,Cookie 保存在客户端(浏览器),Session 保存在服务器端。
  • 存取方式的不同,Cookie 只能保存 字符串,Session 可以存任意数据类型,一般情况下我们可以在 Session 中保持一些常用变量信息,比如说 userId 等。
  • 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。
  • 隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,早期有人将用户的登录名和密码存储在 Cookie 中导致信息被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。
  • 存储大小不同, 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie

注意

  • 一般是Session + Cookie搭配使用,

  • Session只需要在客户端保存一个sessionId,实际上大量数据都是保存在服务端。如果全部用Cookie,数据量大的时候客户端是没有那么多空间的,网络传输的数据量也会随之变大,并且,账户信息全部保存在客户端,一旦被劫持,信息都会泄露

6.禁用Cookie

如果客户端的浏览器禁用了 Cookie 怎么办?

  • 一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。

  • 禁用Cookie,但服务器仍会将sessionIdCookie的方式发送给浏览器,只是,浏览器不再保存这个Cookie(即sessionId)了

7. session的痛点(了解)

实际在生产上,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该打到哪台机器上。

假设登录请求发送到了 A 机器,A 机器生成了 session 并在 cookie 里添加 sessionId 返回给了浏览器,那么问题来了:下次添加购物车时如果请求发送给了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了,此时请问该怎么办。主要有以下三种解决方案

  1. session复制

A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求发送到哪台机器,由于 session 都能找到,故不会有问题

缺点:

  • 同一样的一份 session 保存了多份,数据冗余

  • session数据发生改变,每次都要更新所有节点上的session,当节点多的时候,造成的性能消耗也会很大。

  1. session 粘连

每个客户端请求只发送到固定的一台机器上。若第一次请求时,请求发送给了服务器A,生成了session,那么后续的所有请求,都发送给ANginxsticky 模块可以支持这种方式

缺点:

  • 如果对应的服务器宕机,就无法在别的服务器上获取到session
  1. session 共享(常用)

session 保存在 redis 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可

缺点:

  • 每个请求都要去 redis 取一下 session,多了一次内部连接就消耗了一点性能

8. Storage

作为 Web Storage API 的接口,Storage 提供了访问特定域名下的会话存储或本地存储的功能,例如,可以添加、修改或删除存储的数据项。

如果你想要操作一个域名的会话存储,可以使用 Window.sessionStorage

如果想要操作一个域名的本地存储,可以使用 Window.localStorage

Web Storage的目的是克服由cookie带来的一些限制,当数据需要被严格控制在客户端上时,无需持续地将数据发回给服务器。Web storage主要有两个目的:

  1. 提供一种cookie以外的存储会话数据的方法
  2. 提供一种存储大量的、可以跨会话存在的数据的机制

Storage.key()

该方法接受一个数值 n 作为参数,并返回存储中的第 n 个键名。

  • Storage.getItem()

该方法接受一个键名作为参数,返回键名对应的值。

  • Storage.setItem()

该方法接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。

  • Storage.removeItem()

该方法接受一个键名作为参数,并把该键名从存储中删除。

  • Storage.clear()

调用该方法会清空存储中的所有键名。

StorageEvent 当前页面使用的storage被其他页面修改时会触发StorageEvent事件.

事件在同一个域下的不同页面之间触发,即在A页面注册了storage的监听处理,只有在跟A同域名下的B页面操作storage对象,A页面才会被触发storage事件

8.1 sessionStorage

允许你访问一个,对应当前源的 session Storage对象。存储在 sessionStorage 里面的数据在页面会话结束时会被清除

  • 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。
  • **在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,**这点和 session Cookies 的运行方式不同。
  • 打开多个相同的 URL 的 Tabs 页面,会创建各自的 sessionStorage
  • 关闭对应浏览器标签或窗口,会清除对应的 sessionStorage

8.2 localStorage

允许你访问一个源的对象 Storage,存储的数据将保存在浏览器会话中,并可以长期保留

storage.png