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),所以服务器那边也就没法确认你是你自己。

  • 相关阅读:
    CodeForces Gym 100500A A. Poetry Challenge DFS
    CDOJ 486 Good Morning 傻逼题
    CDOJ 483 Data Structure Problem DFS
    CDOJ 482 Charitable Exchange bfs
    CDOJ 481 Apparent Magnitude 水题
    Codeforces Gym 100637G G. #TheDress 暴力
    Gym 100637F F. The Pool for Lucky Ones 暴力
    Codeforces Gym 100637B B. Lunch 找规律
    Codeforces Gym 100637A A. Nano alarm-clocks 前缀和
    TC SRM 663 div2 B AABB 逆推
  • 原文地址:https://www.cnblogs.com/ethanSung/p/14979630.html
Copyright © 2011-2022 走看看