如何使用redis實現session功能

如何使用redis實現session功能

我們來簡單介紹下redis

redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI?C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。從2010年3月15日起,Redis的開發工作由VMware主持。從2013年5月開始,Redis的開發由Pivotal贊助。

1.與其他用戶狀態保存方案比較

一般開發中用戶狀態使用session或者cookie,兩種方式各種利弊。

Session:在InProc模式下容易丟失,并且引起并發問題。如果使用SQLServer或者SQLServer模式又消耗了性能

Cookie則容易將一些用戶信息暴露,加解密同樣也消耗了性能。

Redis采用這樣的方案解決了幾個問題,

1.Redis存取速度快。

2.用戶數據不容易丟失。

3.用戶多的情況下容易支持集群。

4.能夠查看在線用戶。

5.能夠實現用戶一處登錄。(通過代碼實現,后續介紹)

6.支持持久化。(當然可能沒什么用)

2.實現思路

1.我們知道session其實是在cookie中保存了一個sessionid,用戶每次訪問都將sessionid發給服務器,服務器通過ID查找用戶對應的狀態數據。

在這里我的處理方式也是在cookie中定義一個sessionid,程序需要取得用戶狀態時將sessionid做為key在Redis中查找。

2.同時session支持用戶在一定時間不訪問將session回收。

借用Redis中Keys支持過期時間的特性支持這個功能,但是在續期方面需要程序自行攔截請求調用這個方法(demo有例子)

下面開始代碼說明

3.Redis調用接口

首先引用ServiceStack相關DLL。

在web.config添加配置,這個配置用來設置Redis調用地址每臺服務用【,】隔開。主機寫在第一位

<appsettings>  ????<!--每臺Redis之間用,分割.第一個必須為主機--> ????<add></add></appsettings>

初始化配置

static?Managers() ????????{ ????????????string?sessionRedis=?ConfigurationManager.AppSettings["SessionRedis"]; ????????????string?timeOut?=?ConfigurationManager.AppSettings["SessionRedisTimeOut"];  ????????????if?(string.IsNullOrEmpty(sessionRedis)) ????????????{ ????????????????throw?new?Exception("web.config?缺少配置SessionRedis,每臺Redis之間用,分割.第一個必須為主機"); ????????????}  ????????????if?(string.IsNullOrEmpty(timeOut)==false) ????????????{ ????????????????TimeOut?=?Convert.ToInt32(timeOut); ????????????}  ????????????var?host?=?sessionRedis.Split(char.Parse(",")); ????????????var?writeHost?=?new?string[]?{?host[0]?}; ????????????var?readHosts?=?host.Skip(1).ToArray();  ????????????ClientManagers?=?new?PooledRedisClientManager(writeHost,?readHosts,?new?RedisClientManagerConfig ????????????{ ????????????????MaxWritePoolSize?=?writeReadCount,//“寫”鏈接池鏈接數 ????????????????MaxReadPoolSize?=?writeReadCount,//“讀”鏈接池鏈接數 ????????????????AutoStart?=?true ????????????}); ????????}

為了控制方面寫了一個委托

///?<summary> ????????///?寫入 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<param> ????????///?<returns></returns> ????????public?F?TryRedisWrite<f>(Func<iredisclient>?doWrite) ????????{ ????????????PooledRedisClientManager?prcm?=?new?Managers().GetClientManagers(); ????????????IRedisClient?client?=?null; ????????????try ????????????{ ????????????????using?(client?=?prcm.GetClient()) ????????????????{ ????????????????????return?doWrite(client); ????????????????} ????????????} ????????????catch?(RedisException) ????????????{ ????????????????throw?new?Exception("Redis寫入異常.Host:"?+?client.Host?+?",Port:"?+?client.Port); ????????????} ????????????finally ????????????{ ????????????????if?(client?!=?null) ????????????????{ ????????????????????client.Dispose(); ????????????????} ????????????} ????????}</iredisclient></f>

一個調用的例子其他的具體看源碼

///?<summary> ????????///?以Key/Value的形式存儲對象到緩存中 ????????///?</summary> ????????///?<typeparam>對象類別</typeparam> ????????///?<param>要寫入的集合 ????????public?void?KSet(Dictionary<string>?value) ????????{ ????????????Func<iredisclient>?fun?=?(IRedisClient?client)?=&gt; ????????????{ ????????????????client.SetAll<t>(value); ????????????????return?true; ????????????};  ????????????TryRedisWrite(fun); ????????}</t></iredisclient></string>

4.實現Session

按上面說的給cookie寫一個sessionid

///?<summary> ????///?用戶狀態管理 ????///?</summary> ????public?class?Session ????{ ????????///?<summary> ????????///?初始化 ????????///?</summary> ????????///?<param> ????????public?Session(HttpContextBase?_context) ????????{ ????????????var?context?=?_context; ????????????var?cookie?=?context.Request.Cookies.Get(SessionName); ????????????if?(cookie?==?null?||?string.IsNullOrEmpty(cookie.Value)) ????????????{ ????????????????SessionId?=?NewGuid(); ????????????????context.Response.Cookies.Add(new?HttpCookie(SessionName,?SessionId)); ????????????????context.Request.Cookies.Add(new?HttpCookie(SessionName,?SessionId)); ????????????} ????????????else ????????????{ ????????????????SessionId?=?cookie.Value; ????????????} ????????}  ????}

去存取用戶的方法

///?<summary> ????????///?獲取當前用戶信息 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<returns></returns> ????????public?object?Get<t>()?where?T:class,new() ????????{ ????????????return?new?RedisClient<t>().KGet(SessionId); ????????}  ????????///?<summary> ????????///?用戶是否在線 ????????///?</summary> ????????///?<returns></returns> ????????public?bool?IsLogin() ????????{ ????????????return?new?RedisClient<object>().KIsExist(SessionId); ????????}  ????????///?<summary> ????????///?登錄 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<param> ????????public?void?Login<t>(T?obj)?where?T?:?class,new() ????????{ ????????????new?RedisClient<t>().KSet(SessionId,?obj,?new?TimeSpan(0,?Managers.TimeOut,?0)); ????????}</t></t></object></t></t>

6.續期

默認用戶沒訪問超過30分鐘注銷用戶的登錄狀態,所以用戶每次訪問都要將用戶的注銷時間推遲30分鐘

這需要調用Redis的續期方法

///?<summary> ????????///?延期 ????????///?</summary> ????????///?<param> ????????///?<param> ????????public?void?KSetEntryIn(string?key,?TimeSpan?expiresTime) ????????{ ????????????Func<iredisclient>?fun?=?(IRedisClient?client)?=&gt; ????????????{ ????????????????client.ExpireEntryIn(key,?expiresTime); ????????????????return?false; ????????????};  ????????????TryRedisWrite(fun); ????????}</iredisclient>

封裝以后

///?<summary> ///?續期 ///?</summary> public?void?Postpone() { new?RedisClient<object>().KSetEntryIn(SessionId,?new?TimeSpan(0,?Managers.TimeOut,?0)); }</object>

這里我利用了MVC3中的ActionFilter,攔截用戶的所有請求

namespace?Test { ????public?class?SessionFilterAttribute?:?ActionFilterAttribute ????{ ????????///?<summary> ????????///?每次請求都續期 ????????///?</summary> ????????///?<param> ????????public?override?void?OnActionExecuting(ActionExecutingContext?filterContext) ????????{ ????????????new?Session(filterContext.HttpContext).Postpone(); ????????} ????} }

在Global.asax中要注冊一下

public?static?void?RegisterGlobalFilters(GlobalFilterCollection?filters) ????????{ ????????????filters.Add(new?SessionFilterAttribute()); ????????}  ????????protected?void?Application_Start() ????????{ ????????????RegisterGlobalFilters(GlobalFilters.Filters); ????????}

5.調用方式

為了方便調用借用4.0中的新特性,把Controller添加一個擴展屬性

public?static?class?ExtSessions {public?static?Session?SessionExt(this?Controller?controller) ????{ ????????return?new?Session(controller.HttpContext); ????} }

調用方法:

public?class?HomeController?:?Controller ????{ ????????public?ActionResult?Index() ????????{ ????????????this.SessionExt().IsLogin(); ????????????return?View(); ????????} ????}

6.代碼下載

點擊下載

7.后續

SessionManager包含 獲取用戶列表數量,注銷某個用戶,根據用戶ID獲取用戶信息,在線用戶對象列表,在線用戶SessionId列表等方法

后續將實現用戶一處登錄功能

相關推薦:點擊下載

以上就是如何使用

? 版權聲明
THE END
喜歡就支持一下吧
點贊15 分享