您的位置:首页 > 其它

如何理解session和cookie的关系(例子那是相当的好理解),附带session共享

2018-02-06 10:32 302 查看


为什么有session?

  首先大家知道,http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。 

  那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。 

  原理很简单,假设你访问网页时就像逛澡堂,第一次进去你是没有钥匙的,这个时候你交了钱服务台就分配一把钥匙给你,你走到哪里都要带上,因为这是你身份的唯一标识,接下来你用这把钥匙可以去打开一个专有的储物柜存储你的衣物,游完泳,你再用钥匙去打开柜子拿出衣物,最后离开游泳池时,把钥匙归还,你的这次游泳的过程就是一次session,或者叫做会话,在这个例子中,钥匙就是session的key,而储物柜可以理解为存储用户会话信息的介质。 

  那么在web server中如何实现session呢?想必看了上面的例子你会很容易理解,主要是解决两个问题,一个是钥匙的问题,一个是存储用户信息的问题。对于第一个问题,即什么东西可以让你每次请求都会自动带到服务器呢?如果你比较了解http协议,那么答案一目了然,就是cookie,如果你想为用户建立一次会话,可以在用户授权成功时给他一个cookie,叫做会话id,它当然是唯一的,比如PHP就会为建立会话的用户默认set一个名为phpsessid,值看起来为一个随机字符串的cookie,如果下次发现用户带了这个cookie,服务器就知道,哎呀,刚刚这位顾客来了。 

  剩下的是解决第二个问题,即如何存储用户的信息,服务器知道会话id为abc的用户来了,那abc想存储自己的私人信息,比如购物车信息,如何处理?这个时候可以用内存、也可以用文件,也可以用数据库了,但有个要求是,数据需要用用户的会话id即可取到,比如php就默认会把会话id为abc的用户会话数据存储到/tmp/phpsess_abc的文件里面,每次读取都要反序列化程序可以理解的数据,写的时候又需要序列化为持久的数据格式。


如何实现session的共享?

  首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。 

  事实上,各种web框架早已考虑到这个问题,比如asp.NET,是支持通过配置文件修改session的存储介质为sql server的,所有机器的会话数据都从同一个数据库读,就不会存在不一致的问题;php支持把会话数据存储到某台memcache服务器,你也可以手工把session文件存放的目录改为nfs网络文件系统,从而实现文件的跨机器共享。 

  还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。


SESSION 的数据保存在哪里呢?


PHP中的session存储

  SESSION 的数据保存在哪里呢? 

  当然是在服务器端,但不是保存在内存中,而是保存在文件或数据库中。 

  默认情况下,PHP.ini 中设置的 SESSION 保存方式是 files(
session.save_handler = files
),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 
session.save_path
 指定,文件名以
sess_ 为前缀,后跟 SESSION ID,如:
sess_c72665af28a8b14c0fe11afe3b59b51b
。文件中的数据即是序列化之后的 SESSION 数据了。 

   如果访问量大,可能产生的 SESSION 文件会比较多,这时可以设置分级目录进行 SESSION 文件的保存,效率会提高很多,设置方法为:
session.save_path="N;/save_path"
,N 为分级的级数,save_path 为开始目录。 

   当写入 SESSION 数据的时候,php 会获取到客户端的 SESSION_ID,然后根据这个 SESSION ID 到指定的 SESSION 文件保存目录中找到相应的 SESSION 文件,不存在则创建之,最后将数据序列化之后写入文件。读取 SESSION 数据是也是类似的操作流程,对读出来的数据需要进行解序列化,生成相应的 SESSION 变量。


Java中的session存储

  sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。 

   session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。 

  存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。那么Session在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。

       在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。

       创建:sessionid第一次产生是在直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建。 

  删除:超时;程序调用HttpSession.invalidate();程序关闭。 

  session存放在哪里:服务器端的内存中。不过session可以通过特殊的方式做持久化管理(memcache,redis)。 session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象。 

  session会因为浏览器的关闭而删除吗?不会,session只会通过上面提到的方式去关闭。session不会因为浏览器的
9c41
关闭而删除。但是存有session
ID的cookie的默认过期时间是会话级别。也就是用户关闭了浏览器,那么存储在客户端的session ID便会丢失,但是存储在服务器端的session数据并不会被立即删除。从客户端即浏览器看来,好像session被删除了一样(因为我们丢失了session ID,找不到原来的session数据了)

  
  从浏览器打开访问了某一个网站,关闭浏览器。这样的操作我们算一次“会话”。所以大部分就会认为用户访问了网站就会产生session ID。实际上不然。例如:在Java中我们需要调用HttpServletRequest的getSession方法创建session。

------------------------------------------------------------------------------------------------------------------

     
多说一句: 除了上述提及的方法外,解决session共享问题还有这样一种方式:(实质上并不是通过session的共享来解决的)这里以nginx为例,将用户请求分发到了不同机器上,那么我们只需要固定,同一用户请求分发到同一机器上进行处理,即这一次用户来请求服务器了,那么下一次它再来的时候,同样也请求也被分发到与上一次相同的服务器。这样就确保了同一用户不会因为请求分发到不同机器上而获取不到session数据的问题了。
http://blog.csdn.net/qq_15096707/article/details/74012116
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  session与cookie