cookie和session区别
cookie和session
背景说明
http的无连接与无状态
HTTP协议一共有五大特点:
- 1 支持客户/服务器模式 ;
- 2 简单快速 ;
- 3 灵活 ;
- 4 无连接 ;
- 5 无状态 。
这里主要说明一下无连接和无状态
1、无连接
- 服务器处理完客户的请求,并收到客户的应答后,即断开连接。
- HTTP协议产生于互联网,因此服务器需要处理同时面向全世界数十万、上百万客户端的网页访问,但每个客户端(即浏览器)与服务器之间交换数据的间歇性较大(即传输具有突发性、瞬时性),并且网页浏览的联想性、发散性导致两次传送的数据关联性很低,如果按照上面的方式则需要在服务器端开的进程和句柄数目都是不可接受的,大部分通道实际上会很空闲、无端占用资源。因此HTTP的设计者有意利用这种特点将协议设计为请求时建连接、请求完释放连接,以尽快将资源释放出来服务其他客户端。
Keep-Alive
被提出用来解决效率低的问题。客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接。- http每次响应请求,则要发起一个到服务器的TCP连接,HTTP与服务器之间建立一个连接,而TCP建立连接涉及一个“三次握手”的过程随着时间的推移,html页面变得复杂了,里面可能嵌入了很多图片,这时候每次访问图片都需要建立一次tcp连接就显得低效了。
2、无状态
服务器不知道客户端是什么状态,这意味着每个请求都是独立的,Keep-Alive
没能改变这个结果。
- http协议没法保存客户机信息,也就没法区分每次请求的不同之处。HTTP无状态的特性严重阻碍了这些交互式应用程序的实现,毕竟交互是需要承前启后的。
- 比如记录用户浏览哪些网页、判断用户是否拥有权限访问等。简单的购物车程序也要知道用户到底在之前选择了什么商品。
- 于是,两种用于保持HTTP状态的技术就应运而生了,一个是Cookie,而另一个则是Session。
1、cookie
- HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;
Session 和 Cookie
的主要目的就是为了弥补HTTP的无状态特性
。换句话说,服务器记不住你,可能你每刷新一次网页,就要重新输入一次账号密码进行登录。
1.1、定义
Cookie
:实际上是一小段的文本信息。本质上是http的一个扩展。HTTP 协议中的 Cookie 包括 Web Cookie
和浏览器 Cookie
,它是服务器发送到 Web 浏览器
的一小块数据。服务器发送到浏览器的 Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器。
- 通常,它用于判断两个请求是否来自于同一个浏览器,例如用户保持登录状态。
- 如果
cookie的生存时间
是整个会话期间的话,那么浏览器会将cookie保存在内存
中,浏览器关闭时就会自动清除这个cookie
。 - 另外一种情况就是保存在
客户端的硬盘
中,浏览器关闭的话,该cookie
也不会被清除,下次打开浏览器访问对应网站时,这个cookie
就会自动再次发送到服务器端。
为什么是http的一个扩展?
http头部
是专门负责设置以及发送cookie
的,它们分别是Set-Cookie
以及Cookie
。- 当服务器返回给客户端一个
http响应
信息时,其中如果包含Set-Cookie
这个头部时,意思就是指示客户端建立一个cookie
,并且在后续的http请求中自动发送这个cookie
到服务器端,直到这个cookie过期。
服务器响应报文指示客户端建立一个cookie,并存储
随着对服务器的每个新请求,浏览器将使用 Cookie 头将所有以前存储的 Cookie 发送回服务器。
1.2、作用
cookie 的作用
其实就是这么简单,无非就是服务器给每个客户端(浏览器)打的标签,方便服务器辨认而已。主要有以下几个作用:
- 1、会话管理
登陆、购物车、游戏得分或者服务器应该记住的其他内容 - 2、个性化
用户偏好、主题或者其他设置 - 3、追踪
记录和分析用户行为
1.3、组成(种类和参数)
1.3.1、会话 Cookies 、永久性 Cookies
- 会话 Cookies(Session Cookies),如果
Cookie
不包含到期日期,则将其视为会话 Cookie
。会话Cookie
存储在内存中,永远不会写入磁盘,当浏览器关闭时,此后Cookie
将永久丢失。会话 Cookie
有个特征,客户端关闭时Cookie
会删除,因为它没有指定Expires
或Max-Age
指令。
- 永久性 Cookies(Persistent Cookies),如果
Cookie
包含有效期 ,则将其视为持久性 Cookie
。在到期指定的日期,Cookie
将从磁盘中删除。永久性 Cookie
不会在客户端关闭时过期,而是在特定日期(Expires)
或特定时间长度(Max-Age)
外过期。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
1.3.2、参数
cookie的内容主要包括:名字
,值
,过期时间
,路径
和域
。路径与域
一起构成cookie的作用范围
setcookie()函数向客户端发送一个 HTTP cookie。如果成功,则该函数返回true,否则返回 false。
setcookie(name,value,expire,path,domain,secure)
Domain 和 Path
标识定义了 Cookie
的作用域:即 Cookie
应该发送给哪些 URL
。
Domain 标识
指定了哪些主机可以接受 Cookie。如果不指定,默认为当前主机(不包含子域名)。如果指定了Domain,则一般包含子域名。
- 例如,如果设置
Domain=googlephp.cn
,那么在googlephp.cn
下的所有子域
都有效。- 假设googlephp.cn有两个子域,
php.googlephp.cn
,css.googlephp.cn,
我们设置为setcookie(“user”,”php”,time()+3600,”/”,”php.googlephp.cn”)
,那么只有在php.googlephp.cn
这个子域下才能获取user
这个cookie
变量的值.
- 假设googlephp.cn有两个子域,
- 例如,设置
Path=/docs
,则以下地址都会匹配:- /docs
- /docs/Web/
- /docs/Web/HTTP
1.4、cookie的设置
- 1、客户端请求服务器;
- 2、当接收到客户端发出的 HTTP 请求时,服务器发送带有响应的 Set-Cookie 标头,Cookie通常由浏览器存储。
- 3、对服务器的每个新请求,将 Cookie 与 HTTP标头一同向服务器发出请求。
- 4、服务器检查该Cookie,以此来辨认用户状态。
2、session
很多网站功能很复杂,而且涉及很多的数据交互,比如说电商网站的购物车功能,信息量大,而且结构也比较复杂,无法通过简单的 cookie 机制传递这么多信息,而且要知道 cookie 字段是存储在 HTTP header
中的,就算能够承载这些信息,也会消耗很多的带宽,比较消耗网络资源。
session
就可以配合 cookie
解决这一问题,比如说一个 cookie
存储这样一个变量 sessionID=xxxx
,仅仅把这一个 cookie
传给服务器,然后服务器通过这个 ID
找到对应的 session
,这个 session
是一个数据结构
,里面存储着该用户的购物车等详细信息,服务器可以通过这些信息返回该用户的定制化网页,有效解决了追踪用户的问题。
2.1、定义
Session
是服务器端使用的一种记录客户端状态
的机制,是服务器端为客户端所开辟的存储空间。
- 如果说
Cookie机制
是通过检查客户身上的“通行证”
来确定客户身份的话,那么Session机制
就是通过检查服务器上的“客户明细表”
来确认客户身份
。 Session
相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
2.2、相关参数和函数
这里如果感觉晦涩,可以直接看下一节,更详细说明请参考
客户端请求、服务器读过程,Session如何工作的:
- HTTP请求一个页面后,如果用到开启
session
,会去读cookie
中是否有PHPSESSID
,如果没有,则会新生成一个session_id,
先存入cookie中的PHPSESSID
中,再生成一个sess_前缀文件
。 - 当有写入
$_SESSION
的时候,就会往sess_
文件里序列化写入数据。 - 当读取的
session
变量的时候,先会读取cookie中的PHPSESSID
,获得session_id
,然后再去找这个sess_sessionid文件
,来获取对应的数据。 - 由于默认的
PHPSESSID
是临时的会话,在浏览器关闭后,会消失,所以,我们重新访问的时候,会新生成session_id
和sess_
这个文件。
php.ini
里面有关于session
相关的配置:就是Session如何工作参数设定
[Session]
session.save_handler = files
session.save_path = "d:/wamp/tmp"
session.use_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.serialize_handler = php
session.gc_divisor = 1000
session.gc_probability = 1
session.gc_maxlifetime = 1440
session.save_handler = files
表示的是session的存储方式,默认的是files文件的方式保存,sess_efdsw34534efsdfsfsf3r3wrresa,
保存在session.save_path = "d:/wamp/tmp"
里,所有这2个都是可配值得。我们上面的例子就是用的这种默认的方式。save_handler
不仅仅只能用文件files,还可以用我们常见的memcache 和 redis 来保存。session.use_cookies
默认是1,表示会在浏览器里创建值为PHPSESSID的session_id
,session.name = PHPSESSID
找个配置就是改这个名字的,你可以改成PHPSB
, 那这样就再浏览器里生成名字为PHPSB的session_id 。
session.auto_start =
0用来是否需要自动开启session
,默认是不开启的,所有我们需要在代码中用到session_start();
函数开启,如果设置成1,那么session_id
也会自动就生成了。session.cookie_lifetime = 0
这个是设置在客户端生成PHPSESSID
这个cookie
的过期时间,默认是0
,也就是关闭浏览器就过期,下次访问,会再次生成一个session_id
。所以,如果想关闭浏览器会话后,希望session
信息能够保持的时间长一点,可以把这个值设置大一点,单位是秒
。
2.3、使用
- 服务器第一次接收到请求时,开辟了一块
Session 空间
(创建了Session对象),同时生成一个sessionId
- 通过响应头的
Set-Cookie:JSESSIONID=XXXXXXX
命令,向客户端发送要求设置Cookie
的响应; - 客户端收到响应后,在本机客户端设置了一个
JSESSIONID=XXXXXXX
的Cookie
信息,该Cookie
的过期时间为浏览器会话结束。 - 接下来客户端每次向同一个网站发送请求时,请求头都会带上该
Cookie 信息
(包含sessionId
), - 然后,服务器通过读取请求头中的
Cookie 信息
,获取名称为JSESSIONID
的值,得到此次请求的sessionId
。
注意:
Session的有效期:
- 由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把
长时间内没有活跃
的Session
从内存删除。这个时间就是Session的超时时间
。如果超过了超时时间没访问过服务器,Session
就自动失效了。 session.cookie_lifetime = 0
这个是设置在客户端生成PHPSESSID
这个cookie
的过期时间,默认是0
,也就是关闭浏览器就过期,下次访问,会再次生成一个session_id
。所以,如果想关闭浏览器会话后,希望session
信息能够保持的时间长一点,可以把这个值设置大一点,单位是秒
。
2.4、session 的实现(服务器如何设计的存储和查找结构)
session 的原理不难,但是具体实现它可是很有技巧的,一般需要三个组件配合完成,它们分别是 Manager
、Provider
和 Session
三个类(接口)。
角色扮演作用:
- Handler :解析
HTTP header 中的 cookie
,得到sessionID
- Manager:充当一个
session
管理器,存储一些配置信息 - Provider :一个容器,最常见的是散列表,
sid
和对应的session
一 一 映射
图解流程:
- 1、浏览器通过
HTTP
协议向服务器请求路径/content
的网页资源,对应路径上有一个Handler 函数
接收请求,解析HTTP header 中的 cookie
,得到其中存储的sessionID
,然后把这个ID
发给Manager
。 - 2、
Manager
充当一个session
管理器的角色,主要存储一些配置信息,比如session 的存活时间
,cookie 的名字
等等。而所有的session
存在Manager
内部的一个Provider
中。所以Manager
会sid(sessionID)
传递给Provider
,让它去找这个ID
对应的具体是哪个session
。 - 3、
Provider
就是一个容器,最常见的应该就是一个散列表,将每个sid
和对应的session
一一映射起来。收到Manager
传递的sid
之后,它就找到sid
对应的session
结构,也就是Session
结构,然后返回它。 - 4、
Session
中存储着用户的具体信息,由Handler
函数中的逻辑拿出这些信息,生成该用户的 HTML 网页,返回给客户端。
为什么搞这么麻烦,直接在 Handler 函数中搞一个哈希表,然后存储 sid
和 Session
结构的映射不就完事儿了?
解释如下:
1、先从最底层的 Session 说。既然 session 就是键值对,为啥不直接用哈希表,而是要抽象出这么一个数据结构呢?
-
第一,因为
Session 结构
可能不止存储了一个哈希表,还可以存储一些辅助数据,比如sid
,访问次数
,过期时间
或者最后一次的访问时间
,这样便于实现想 LRU、LFU 这样的算法。 -
第二,因为
session
可以有不同的存储方式。如果用编程语言内置的哈希表,那么session
数据就是存储在内存中,如果数据量大,很容易造成程序崩溃,而且一旦程序结束,所有session
数据都会丢失。所以可以有很多种session
的存储方式,比如存入缓存数据库 Redis,或者存入 MySQL 等等。
因此,Session 结构提供一层抽象,屏蔽不同存储方式的差异,只要提供一组通用接口操纵键值对。
2、Provider 为啥要抽象出来?
Provider
就是一个散列表,保存 sid
到 Session
的映射,但是实际中肯定会更加复杂。我们不是要时不时删除一些 session
吗,除了设置存活时间
之外,还可以采用一些其他策略,比如 LRU 缓存淘汰算法,这样就需要 Provider 内部使用哈希链表这种数据结构来存储 session。
因此,Provider 作为一个容器,就是要屏蔽算法细节,以合理的数据结构和算法组织 sid 和 Session 的映射关系
3、Manager 为啥要抽象出来?
大部分具体工作都委托给 Session
和 Provider
承担了,Manager
主要就是一个参数集合
,比如 session 的存活时间
,清理过期 session 的策略
,以及 session 的可用存储方式
。
Manager
屏蔽了操作的具体细节,我们可以通过 Manager 灵活地配置 session 机制。
2.5、不同场景下的session(判断是否是相同的session)
- 当在同一个浏览器中同时打开多个标签,发送同一个请求或不同的请求,仍是同一个session;
- 当不在同一个窗口中打开相同的浏览器时(打开多个相同的浏览器),发送请求,仍是同一个session;
- 当使用不同的浏览器时,发送请求,即使发送相同的请求,是不同的session;
- 当把当前某个浏览器的窗口全关闭,再打开,发起相同的请求时,是不同的session。
3、常见面试问题
3.1、Cookie和Session区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
3.2、cookie被禁用,如何使用session
- 经常被使用的一种技术叫做
URL重写
(基本这么回答),就是把session id直接附加在URL路径的后面。 - 还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
<form name=”"testform”" action=”"/xxx”">
<input type=”"hidden”" name=”"jsessionid”" value=”"ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764″”/>
<input type=”"text”">
</form>
3.3、浏览器关闭后,session就销毁了吗?
参考
浏览器关闭和服务器session销毁没有任何关系,会话Cookie(非持久cookie)在关闭浏览器后就会消失,但是原来服务器的Session还在,只有等到了销毁的时间会自动销毁。
参考
1、https://blog.csdn.net/weixin_42419856
2、https://mp.weixin.qq.com/s/Q1BUuQbxhnp4V9d8-8XscQ
3、https://blog.csdn.net/think2me/article/details/38726429
4、https://labuladong.gitbook.io/algo/di-wu-zhang-ji-shu-wen-zhang-xi-lie/session-he-cookie