Session 详解

 

Session 详解

引子

想一个问题, 有一个商店要做一个活动,对于在本店累计消费超过2000元的客户 ,可以领取小礼品一份。要如何实现 。

  1. 每次消费给客户一张消费凭证如发票等 ,用户兑奖把这些发票都带过来 。
  2. 给客户办一张会员卡,客户结账时出示会员卡,收银员可以在商店的管理系统查到客户的历史消费记录 ,然后兑奖。

是什么

字面意思 会话(对话) ,会话机制 ,客户端发起对话,服务端回答,经过多次对话后,让服务端拥有知道之前和某个客户聊了什么的机制 。

其他

  • session 是一种服务端机制 ;
  • 因为http协议无状态,所有需要状态管理 ( 记得上一讲 ,为什么有cookie 也是这个原因么 );
  • 不同web平台都有对session机制的实现;

建立会话:

客户端请求服务端,服务端检测这边有没有存储和这个客户的对话。如果没有就建立会话 ,有的话继续维护当前会话。(思考问题,通过什么检测有没有和这个客户的对话)

断开会话:

服务端销毁某个会话数据,会使其断开;客户端长时间不访问服务端,根据配置的session过期时间,服务端会销毁和某个客户端会话数据。
同时,客户端也可以断开会话,只需要客户端不告诉服务端sessionid,或者换一个开启一段新的会话。

分清楚一个概念:会话状态和登录状态的区别

会话状态虽然常常被用来标识登录状态。但是却不能完全等同 ;登录状态很好理解,用户没有登录之前,是未登录状态。 输入账号密码(或其他方式)登录验证成功之后是 已登录状态。
那什么时候开始有会话状态的呢 ?
举一个例子来证明没有登录,会话状态已经产生了 :比如登录或者注册时的图形验证码 。

不同web平台中对session的实现

不同web开发框架都有对session机制的 实现,或者叫封装 ,常见的平台如下图:

平台 核心对象 默认存放sessionId的cookie name 使用语法
c# System.Web.SessionState.HttpSessionState ASP.NET_SessionId Session[""]=3;
php $_SESSION PHPSESSID $_SESSION['33']=1;
java javax.servlet.http.HttpSession JSESSIONID HttpSession session = request.getSession(); session.setAttribute("data", "sfe");

Asp.net 对Session的实现

我们从Session在web.config文件中的配置讲起:参考

  • session在web.config中的配置
<sessionState
mode="[Off|InProc|StateServer|SQLServer|Custom]"
timeout="number of minutes"
cookieName="session identifier cookie name"
cookieless=
"[true|false|AutoDetect|UseCookies|UseUri|UseDeviceProfile]"
regenerateExpiredSessionId="[True|False]"
sessionIDManagerType="session manager type"
sqlConnectionString="sql connection string"
sqlCommandTimeout="number of seconds"
allowCustomSqlDatabase="[True|False]"
useHostingIdentity="[True|False]"
stateConnectionString="tcpip=server:port"
stateNetworkTimeout="number of seconds"
customProvider="custom provider name"
compressionEnabled="[True|False]"
sqlConnectionRetryInterval="number of seconds">
<providers>...</providers>
</sessionState>

挑几个关键属性讲下:

  • mode
    • Off: 关闭,不使用cookie
    • InPro: 当前进程,也就是w3wp进程
    • SQLServer :会话状态正在使用进程外 SQL Server 数据库存储状态信息。Aspnet_regsql.exe 工具
    • StateServer:会话状态将使用进程外 ASP.NET 状态服务来存储状态信息, windows服务aspnet_state.exe
    • Custom : 自定义,自己实现SessionStateStoreProviderBase这个抽象类就可以了,然后配置:
<sessionState mode="Custom" customProvider="MySessionStateStore">
<providers>
<clear/>
<add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" connectionString="RedisConnection"/>
</providers>
</sessionState>
  • cookieless
    • AutoDetect :session机制根据浏览器对cookie的支持情况决定是使用cookie还是url传递sessionid
    • UseCookies :显式指定使用cookie 传递sessionid【推荐
    • UseDeviceProfile :session机制根据浏览器对cookie的支持情况决定是使用cookie还是url传递sessionid
    • UseUri: 显式指定用url传递sessionid

常见Session丢失原因

1、Session超时,用户打开页面,页面长时间不操作会导致此原因

2、IIS应用程序池回收,或者重启

3、Web.Config修改,即IIS应用程序池重启

4、dll被替换或者动态页面修改,即IIS应用程序池重启

5、杀毒软件对.config文件进行扫描,可能会导致IIS应用程序池回收

6、用户浏览器禁用cookie

7、其他原因

asp.net Session 进阶

Session 共享

两个网站会话共享, a网站登录,b网站也登录了,根据session的原理 ,session是通过客户端的cookie里的sessionid 来识别同一个用户发来的请求,所以这里这里就是要连个网站sessionid一样 ,也就是cookie相同,但是cookie是不能跨域传输的,但是只要主域一样 ,将cookie的域设置成domain.com ,cookie会发送到这个主域下所有子域对应的网站。
是否发送到两个网站服务端的sessionid一样,session就共享了呢,其实不然 ,
如果session mode 是Inpro 模式,这明显不行,因为session存在各自的网站进程里面,
如果session mode是 stateServer模式呢 ,其实也不行,需要进行一些小修改就好,因为session的存储结构不单单是 sessionid 和session里面的内容 ,他是sessionid 和网站唯一标志共同来唯一指定的,我们可以通过一些手段骗session机制,两个不同的网站的唯一标志是一样的。
session mode 是sqlserver 和上面的方案差不多,也是要进行些修改,让网站标志一样 。
可以看到实现session的共享还是很麻烦的。

  1. 设置存储sessionid的cookie的域是主域
  2. 将session存在 stateserver 或者sqlserver (性能会有所影响) ,
  3. 骗asp.net session机制,不同网站的网站唯一标志是一样的。

网站负载了 Session 还可用么

这个问题还需要有负载均衡相关知识才能了解,简而言之,同样的web程序部署多个,客户端发出的请求根据算法分配到其中某一个服务端处理。
首先可以确定,发送到多个程序的sessionid是一样的,接着就是服务端能根据sessionid获取到同样的会话数据吗?
这个问题和上面很像 ,是不能的,因为网站的标志不一样的。说解决方案也和上面差不多了,少了第一步。

Session 的并发缺点

微软官方的几种sessionmode provider 都有这个问题,在一段会话里面 ,服务端会按照循序处理客户端发过来的会话请求 ,也就是说,上一个请求没处理完,浏览器就发起了下一个请求的话会被挂起,直到上一个会话请求处理完成。这种并发情况可能常见于一个页面上对服务端发出多个异步请求,如果某个请求处理时间很长 ,后面就请求就会被挂起。虽然.net 提供了关闭某个地址session的配置,但是通常业务场景中都是需要会话状态的。

不用Asp.net Session 用什么

我们把这个问题转换一下,因为

常见的session使用场景是

  1. 存储验证码
  2. 存储用户基础信息,如id ,姓名,角色等
  3. 作为身份验证,登录验证
  4. 多个页面间传值
  5. ???

那么就是找到处理这些场景问题解决方案就可以了 。
能不能把用cookie加密存储。 或者cache +cookie ,redis +cookie ,
另外身份验证可以用。net自带 forms 身份验证。

Q&A

  1. 为什么session(如果作为登录状态,那就会造成重新登录)莫名其妙丢失 ?
  2. 向session里面写数据时报错 ,无法序列化
    无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP.NET 将序列化会话状态对象,因此不允许使用无法序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“Custom”模式下执行了类似的序列化,则适用同样的限制。
  3. 用来承载会话的cookie ,有什么特征。
  4. 如果让你实现一个简单的session机制需要做哪些事 。
posted @ 2018-04-10 10:44  地菜  阅读(501)  评论(0编辑  收藏  举报