由于http的无状态性,设计了cookie机制,这样可以识别出是否已经访问过,可以针对性的做一些缓存,减少服务器压力。
在http第一次访问某网站时,php会先判断该客户端是否是第一次访问(是否有PHPSESSID),如果没有那么php设置该值并在响应报文的响应头中以set_cookie返回,如果不是第一次访问,那么后面客户端都会在请求头将所有cookie以Cookie为键带到服务器。
PHPSESSID无论session_start()是否开启,第一次访问都将创建。
在刚创建cookie时设置一个cookie值,是无法在本次执行过程中获得的,因为php还没有以响应报文的形式将该cookie值带到客户端,当该cookie值到达客户端并保存后,在之后的程序中即可获取该值。
然而在这么多的cookie值中,有一个特殊的cookie值就是PHPSESSID,这个值就是在php中用来维持session会话的(该值可在php配置文件中进行更改),在到服务端时会检测该值是否存在,如不存在则创建。
一个域名下的session的所有值都是存储在服务器端的一个文件中,且PHPSESSID的值是跟该文件的名字一样。
那么问题来了,session会话是通过cookie值实现的,那如果cookie值被禁用掉session还能实现吗?
这个是可以实现的,我们尝试用以下几种方法实现:
我们在火狐浏览器中把所有cookie全部阻止掉,这样的话,服务器端是可以在响应头中设置cookie,可是浏览器并不接收,在请求头中也不会带有该网站中的任何cookie。在实验前如果php.ini中session.auto_start该值设为0。
在没有cookie之后,http将无法识别客户端是否访问过,每一次的访问都会被视为第一次访问,PHPSESSID的值不断改变,存储session的文件也不断增加。导致你无法获取上一次你所设下的session值。也就是服务器端已经不认识你了。如果我们仍要保持该session会话,那我们必须向服务器端传递一个固定的PHPSESSID,因为该值会被作为文件存储在服务器上。如果该值一定之后,那么我们每次都是在那个文件里取值。请求头上面已不能传递cookie值,但是我们可以从http请求包中的其他方法传递(请求路径上,请求主体中),也就是我们经常所说的get或者post方式传递一个PHPSESSID值。
1.路径为http://www.meiyong.com/test.php?PHPSESSID=yzlcxh通过get方式传递上去(这是我自己的本地域名)
session_id($_GET['PHPSESSID']);
session_start();
//$_SESSION['name'] = 'hello';
echo $_SESSION['name'];
这是php代码,这是通过session_id(一定要放在session_start之前)函数实现的,这样以后每一次传递都带上PHPSESSID=yzlcxh那么就能维持该session会话了
也可以通过post方式,在表单提交时增加隐藏框,把该值传递上去,也能做到同样的效果,推荐用post方式吧(更安全,别人也看不出来你在干什么)。
2.第二种方法是想用ajax(jquery的一种异步请求)在前端发起请求的时候,设置请求头Cookie:PHPSESSID=yzlcxh。不过这个方法失败了,Refused to set unsafe header "Cookie",规定不能手动设置请求头Cookie,所以暂时只想到了第一种方法是可以实现的。
在理解了session的运行机制之后,我们可以考虑实现一下session共享。
如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。
1. 基于NFS的Session共享
NFS是Net FileSystem的简称,最早由Sun公司为解决Unix网络主机间的目录共享而研发。
这个方案实现最为简单,无需做过多的二次开发,仅需将共享目录服务器mount到各频道服务器的本地session目录即可,缺点是NFS依托 于复 杂的安全机制和文件系统,因此并发效率不高,尤其对于session这类高并发读写的小文件, 会由于共享目录服务器的io-wait过高,最终拖累前端WEB应用程序的执行效率。
2. 基于数据库的Session共享
首选当然是大名鼎鼎的Mysql数据库,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普 遍在 使用,它的缺点在于session的并发读写能力取决于Mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。
3. 基于Cookie的Session共享
这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的Session信息加密、序列化后以Cookie的方式, 统一 种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现 用户的Cookie化Session 在多服务间的共享访问。
这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信心长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带 宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器。
4. 基于Memcache的Session共享
Memcache由于是一款基于Libevent多路异步I/O技术的内存共享系统,简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。
另外值得一提的是Memcache的内存hash表所特有的Expires数据过期淘汰机制,正好和Session的过期机制不谋而合,降低了 过期Session数据删除的代码复杂度,对比“基于数据库的存储方案”,仅这块逻辑就给数据表产生巨大的查询压力。
最后就是session和cookie的区别:
1.存放的位置
cookie保存在客户端,session一般保存在服务器端的文件系统或数据库或mamcache
2.安全性
由于session存放在服务器端,cookie存在于客户端可以直接在浏览器上查到并更改,所以cookie的安全性较session弱
3.网络传输量
cookie需通过网络实现客户端与服务器端之间的传输,而session保存在服务器端,无需传输
4.生存时间(以设置24分钟为例)
(1)cookie的生命周期是累计的。从创建的时候就开始计时,24分钟后cookie生命周期结束,cookie自动失效
(2)session的生命周期是间隔的,从创建时开始计时,比如在24分钟内(php.ini默认session的失效时间就是1440s,即24m)没有访问过session(指没有执行含session的文件),那么session信息就自动无效,但如果在24分钟之内,比如第23分钟访问过session,那么它的生命周期将重新开始计算。
5.所存储内容的大小
cookie实在客户端键值方式存储的,数据量有所限制,但是session在服务端用文本存储是可以无限量的。