zoukankan      html  css  js  c++  java
  • 聊聊Cookie和Session

    本篇文章参考来自购买的 bravo1988 - 知乎 (zhihu.com)的java小册!!!

    1.什么是Http协议

    ​ 做javaWeb相关的都知道Http协议的规则是请求和响应的,请求-响应这种通信模式,即服务器不会主动搭理客户端,只是被动地响应客户端的请求。最重要的一个特性是无状态的,什么是无状态呢,就是每次请求对于服务器来说都是全新的请求,即使浏览器那边是同一个发出的,服务器是无法识别浏览器发出的请求是谁,是否之前请求过,所以也就导致了一个问题,既然是无状态的,那么我们登录购物网站,登录论坛,是如何确认到是我们的账号登录并操作的,这就是Cookie和Session作用所在。

    2. 什么是会话机制(Session)

    会话机制最主要的目的是帮助服务器记住客户端状态(标识用户,跟踪状态)。

    有了会话机制,那么服务器就可以识别客户端/浏览器,就可以将同一个用户发出的请求归类在一起,例如,你淘宝购物车你添加了一些商品后,不可能重新打开淘宝后购物车中的商品变成你女朋友的添加的商品。

    所以理解的重点就是:

    1. 首先明白http协议是无状态的,并且理解什么是无状态;
    2. 然后明白无状态的http协议有哪些不足,于是会话机制弥补了http协议因为无状态产生的缺陷;

    会话机制的定义 :

    ​ 是一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。

    ​ 会话,指用户登录网站后的一系列动作,比如浏览商品添加到购物车并购买。会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定

    注意:Session翻译过来就是会话机制,这种机制的实现在规则和代码层面又有两种类型分别叫做Cookie和Session

    3. 如何定义一次会话

    在计算机的世界中,会话又是什么?大家可能早就听过这句话:

    从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话。

    我们会有以下的疑问:

    1. 为什么浏览器关闭代表一次会话结束?

    2. 关闭时发生了什么操作导致会话结束?

    3. 为什么那个操作执行意味着会话结束?

      归根揭底,我们只需要明白什么才能代表一次完整的会话!!!

      一个会话可以帮助服务器断定一个客户端,那么反向推导得到的结论就是:当服务器无法断定客户端时,一次会话就结束了!

    服务器什么情况下无法断定一个客户端?无非两种情况:

    • 服务器识别不到session了(session失效)
    • 客户端没有携带Cookie访问服务器(cookie失效)

    又基于上面分析,可以总结出一次会话存在的基本原则:

    • 双方共存(cookie与session同时存在)

    4. 认识Cookie

     Cookie实际上是一小段的文本信息。客户端第一次发出请求,请求服务器时,如果服务器需要记录该用户状态,就会使用response向客户端浏览器响应回一个Cookie。客户端会把Cookie保存起来,保存在浏览器的内存中

    疑问:是否客户端的第一次请求肯定会响应回一个cookie?

     当浏览器再次请求该网站时,浏览器发出的请求中会携带着该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

    其实Cookie可以分为两种:

    • 会话Cookie (Session Cookie)
    • 持久性Cookie (Persistent Cookie)

    会话Cookie:

    被保存在浏览器的内存中,当浏览器关闭时,内存被释放,内存中的Cookie自然也就烟消云散。这样太麻烦了,关闭浏览器引发Cookie消失,下次还要重新登录。能不能向客户端响应持久性Cookie呢?只要设置Cookie的持久化时间即可!查看对应的API可以设置。

    对于每种不同的浏览器,不管是会话Cookie还是持久性Cookie,都是相对独立的,每家浏览器厂商会话Cookie(保存在浏览器内存中)和持久性Cookie(保存在电脑某个浏览器设定的文件夹中)存储的位置是不同的。所以,当你用Chrome登录京东,你再用IE打开京东时,仍旧要登录,因为你没有带去标识用户信息的Cookie(不论是会话Cookie还是持久性Cookie,IE都拿不到Chrome的)。

    小结一下:

    • 不设置MaxAge,默认响应会话Cookie(MaxAge<0),存在浏览器内存。Cookie随浏览器关闭而消失。
    • 设置MaxAge>0,响应持久性Cookie,会存在电脑硬盘的特定文件夹下(浏览器自定义的),这样你关闭浏览器后在有效时间内请求服务器仍然可以是登录状态。
    • 设置特定Cookie的MaxAge=0,则会删除已经存在客户端的此Cookie。

    一般,响应给客户端的Cookie都是会话Cookie(不设置MaxAge),是存在浏览器内存中的。所以关闭浏览器后,内存中Cookie就消失了。Cookie消失,则下次请求服务器时,请求头中不存在代表用户信息的Cookie(唯一标识用户,表示其状态),那么浏览器就无法识别请求的用户。

    根据我们上面反向推导的结论:当服务器无法断定客户端时,一次会话就结束了!

    5. 认识Session

    ​ 有了Cookie,似乎已经能解决问题,为什么还需要Session?原因似乎可以列举很多,有可能是出于安全性和传输效率的考虑。首先,Cookie是存在客户端的,如果保存了敏感信息,会被其他用户看到。其次,如果信息太多,可能影响传输效率。

    相比较Cookie存在客户端,Session则是服务端的东西。其本质上类似于一个大Map,里面的内容,以键值对的形式存储。

    每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。其实,只要你在服务器端创建了Session,即使不写addCookie("JSESSIONID", id),JSESSIONID仍会被作为Cookie返回。

    ​ 要注意的是,Session有个默认最大不活动时间:30分钟(可在配置文件中修改数值)。也就是说,创建Session并返回JSESSIONID给客户端后,如果30分钟内你没有再次访问,即使你下次再带着JSESSIONID来,服务端也找不到对应ID的Session了,因为它已经被销毁。此时你必须重新登录。

      我们需要知道:

      1)SessionId的重要性:
      什么东西可以让你每次请求都把SessionId自动带到服务器呢?显然就是cookie了,如果你想为用户建立一次会话,可以在用户授权成功时给他一个唯一的cookie。当一个用户提交了表单时,浏览器会将用户的SessionId自动附加在HTTP头信息中,其实也就是请求中带着Cookie(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionId所对应的用户。试想,如果没有 SessionId,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。

      2)储存需要的信息。服务器通过SessionId作为key,读写到对应的value,这就达到了保持会话信息的目的。

    6. session的序列化

    ​ 所谓Session序列化,其实是一个默认行为。它存在的意义在于:比如现在有成千上万个用户在线,用户登录信息都在各自的Session中。当服务器不得不重启时,为了不让当前保存在服务器的Session丢失,服务器会将当前内存中的Session序列化到磁盘中,等重启完毕,又重新读取回内存。这些操作浏览器端用户根本感知不到,因为session还在,他不用重新登录。以Tomcat为例,服务器的Session都会被保存在work目录的对应项目下。关闭服务器时,当前内存中的session会被序列化在磁盘中,变成一个叫SESSIONS.ser的文件。

    7. 钝化和活化

    ​ 自从改用Session后,由于Session都存在服务器端,当在线用户过多时,会导致Session猛增,无形中加大了服务器的内存负担。于是,服务器有个机制:如果一个Session长时间无人访问,为了减少内存占用,会被钝化到磁盘上。也就是说,Session序列化不仅仅是服务器关闭时才发生,当一个Session长时间不活动,也是有可能被序列化到磁盘中。当该Session再次被访问时,才会被反序列化。这就是Session的钝化和活化。可以在Tomcat的conf目录下的context.xml中配置(对所有项目生效。

    还有个问题需要解决:Session被序列化了,存在Session中的值怎么办?比如存在session中的是一个entity类的对象?

    HttpSession session= request.getSession();
    session.setAttribute("user", new User("eekk", 26));
    

    此时Session中有一个User对象,那么User对象去哪了?答案是,User从内存中消失,无法随Session一起序列化到磁盘。如果希望Session中的对象也一起序列化到磁盘,该对象必须实现序列化接口。

    总结:

    1. 我们需要知道cookie保存在客户端,session保存在服务端,cookie的产生是在服务端产生的,是浏览器第一次请求服务器,服务器响应给浏览器一个Cookie

    2. cookie只是一个通行证,但并不是安全的,任何安全的校验必须要在服务端上完成,cookie只是存在客户端上面的一个唯一标识它且由服务端定制的信息,本地可以改,但是不管怎么改,最后还是需要把它拿上发送给服务端进行匹配校验。

    3. session和cookie的存储都存在时效性,这是很有必要的

    4. 不管是cookie还是session,都是建立在安全性的大前提下,session中不仅仅有cookie的信息,同时会有该用户的相关重要且安全的信息存储,所以session是在服务器的,而cookie只是服务器将一些不重要的信息拿出来丢给客户的存在,以备以后快速匹配校验用。

    5. 回到一个最值得思考的问题:

      1. 会话是如何建立起来的?

        一次会话的建立就是浏览器第一次请求服务器,服务器响应回浏览器之前,会生成一个保存该浏览器用户信息的session,并放在浏览器,然后响应回浏览器的时候,将一个cookie交给浏览器,浏览器保存起来这个cookie,这样,就是建立以一次会话的开始。

      2. 什么是一次会话?是在什么时候结束的?

        一次完整的会话就是在一次会话建立之后,在浏览器上的coolie和服务器上的session都还存在并且相互间可以验证对方的时候。

        那么反推结束的时候就是浏览器上的coolie和服务器上的session只要有任何一方都失效,双方无法进行互相验证的时候,就代表会话结束了。

        所以服务器能“知道”浏览器关了,是因为浏览器请求下次再来的时候,并没有带来上次给它的cookie。你无法证明你还是你。其实不一定是浏览器关了,也可能是清缓存了。总之,一次会话已经结束。这样理解:浏览器确实给服务器发了请求,但是请求中没有携带证明自己的身份证号(Cookie),所以服务器那边也就没法确认你是你自己。

  • 相关阅读:
    bzoj 1503
    bzoj 1193 贪心+bfs
    bzoj 1798 线段树
    Codeforces 804D Expected diameter of a tree
    bzoj 1208
    bzoj 3224
    HDU 5115 区间dp
    hihocoder #1162 矩阵加速dp
    分块入门
    bzoj 1036 树链剖分
  • 原文地址:https://www.cnblogs.com/ethanSung/p/14979630.html
Copyright © 2011-2022 走看看