首页 > 代码库 > Nginx+IIS+Redis 处理Session共享问题 1

Nginx+IIS+Redis 处理Session共享问题 1

      最近遇到一个棘手的问题,微信公众平台的前端站点session老是丢失,我们是走的微信网页授权,授权后获取用户openid,丢失后没有openid后续的操作全白搭了,因为没了openid只能判断为客户不是在微信端访问进行提示,

然后接连收到客服中心回馈问题,不过全是安卓客户端的ios的完全没有(真邪门了),哎,秉着有问题就要解决的态度,开搞吧!

      我们前端有六台Windows server 2012,部署的IIS站点,用A10做的硬负载,之前openid都是作为url参数各个page进行传递的,领导有意见,因为作为url参数的话微信的分享功能可以把整段链接分享出去,后来我们把分享按钮屏蔽掉了,不过效果还是不太好,手微信页面加载慢的时候屏蔽的js还没生效还是能复制到链接什么的,后来改成了session,所以考虑到应该在请求分发下六台服务器session没同步导致的!

技术分享

      之前也看过写关于分布式下session的问题,然后自己也想了想,试着用redis+Cookie的方案来试下,这个方案也有两种用法,目前只使用了第一种,第二种是为了防止第一种失败考虑的,下面大概先说下方案。

     用户授权后,任意站点拿到openid后生成guid作为sessionId 写到cookie, 然后将sessionId+自定义key作为rediskey,然后将openid作为redisvalue写入redis,redis跟cookie的写入都是有时效性的,如果中途请求分发到别的服务器就直接拿cookie然后组装rediskey去查询,如果没有那就认为客户不是正常手段进入页面的,如果有就拿openid进行下面业务操作,见图:

技术分享                技术分享

     两种方案大体相同,方案二只是考虑如果cookie不能写的话继续采取url参数传递,redis 的key有过期策略,就算分享出去也是一定时间内有效。

下面给出代码:

     技术分享

首先建站点 SessionManagerDemo  Default页面就是简单的 get set

技术分享
    protected void Page_Load(object sender, EventArgs e)        {            SessionHelper sessionHelper = new SessionHelper();            sessionHelper["test123"] = "session 共享测试!";            Response.Write("session:" + sessionHelper["test123"]);        }
Default.aspx

建类库 SessionManager  这里用的是StackExchange.Redis  园里有写介绍文章还有使用demo 我也是找了个自己试试,感觉挺好,代码贴出来大家可以自己试着看看

首先是 RedisConnectionHelp.cs

技术分享
 /// <summary>    /// ConnectionMultiplexer对象管理帮助类    /// </summary>    public static class RedisConnectionHelp    {        //系统自定义Key前缀        public static readonly string SysCustomKey = ConfigurationManager.AppSettings["redisKey"] ?? "";        //"127.0.0.1:6379,allowadmin=true        private static readonly string RedisConnectionString = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;        private static readonly object Locker = new object();        private static ConnectionMultiplexer _instance;        private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>();        /// <summary>        /// 单例获取        /// </summary>        public static ConnectionMultiplexer Instance        {            get            {                if (_instance == null)                {                    lock (Locker)                    {                        if (_instance == null || !_instance.IsConnected)                        {                            _instance = GetManager();                        }                    }                }                return _instance;            }        }        /// <summary>        /// 缓存获取        /// </summary>        /// <param name="connectionString"></param>        /// <returns></returns>        public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString)        {            if (!ConnectionCache.ContainsKey(connectionString))            {                ConnectionCache[connectionString] = GetManager(connectionString);            }            return ConnectionCache[connectionString];        }        private static ConnectionMultiplexer GetManager(string connectionString = null)        {            connectionString = connectionString ?? RedisConnectionString;            var connect = ConnectionMultiplexer.Connect(connectionString);            //注册如下事件            connect.ConnectionFailed += MuxerConnectionFailed;            connect.ConnectionRestored += MuxerConnectionRestored;            connect.ErrorMessage += MuxerErrorMessage;            connect.ConfigurationChanged += MuxerConfigurationChanged;            connect.HashSlotMoved += MuxerHashSlotMoved;            connect.InternalError += MuxerInternalError;                        return connect;        }        #region 事件        /// <summary>        /// 配置更改时        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)        {            Console.WriteLine("Configuration changed: " + e.EndPoint);        }        /// <summary>        /// 发生错误时        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)        {            Console.WriteLine("ErrorMessage: " + e.Message);        }        /// <summary>        /// 重新建立连接之前的错误        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)        {            Console.WriteLine("ConnectionRestored: " + e.EndPoint);        }        /// <summary>        /// 连接失败 , 如果重新连接成功你将不会收到这个通知        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)        {            Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));        }        /// <summary>        /// 更改集群        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)        {            Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);        }        /// <summary>        /// redis类库错误        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private static void MuxerInternalError(object sender, InternalErrorEventArgs e)        {            Console.WriteLine("InternalError:Message" + e.Exception.Message);        }        #endregion 事件    }
RedisConnectionHelp

然后 RedisHelper 实际操作类  这里 string、hash、list、SortedSet等等的一些操作全有了,同步的异步的也是满满的

技术分享
 /// <summary>    /// Redis操作    /// </summary>    public class RedisHelper    {        private int DbNum { get; set; }        private readonly ConnectionMultiplexer _conn;        public string CustomKey;        #region 构造函数        public RedisHelper(int dbNum = 0)            : this(dbNum, null)        {        }        public RedisHelper(int dbNum, string readWriteHosts)        {            DbNum = dbNum;            _conn =                string.IsNullOrWhiteSpace(readWriteHosts) ?                RedisConnectionHelp.Instance :                RedisConnectionHelp.GetConnectionMultiplexer(readWriteHosts);        }        #endregion 构造函数        #region String        #region 同步方法        /// <summary>        /// 保存单个key value        /// </summary>        /// <param name="key">Redis Key</param>        /// <param name="value">保存的值</param>        /// <param name="expiry">过期时间</param>        /// <returns></returns>        public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?))        {            key = AddSysCustomKey(key);            return Do(db => db.StringSet(key, value, expiry));        }        /// <summary>        /// 保存多个key value        /// </summary>        /// <param name="keyValues">键值对</param>        /// <returns></returns>        public bool StringSet(List<KeyValuePair<RedisKey, RedisValue>> keyValues)        {            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();            return Do(db => db.StringSet(newkeyValues.ToArray()));        }        /// <summary>        /// 保存一个对象        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="obj"></param>        /// <param name="expiry"></param>        /// <returns></returns>        public bool StringSet<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))        {            key = AddSysCustomKey(key);            string json = ConvertJson(obj);            return Do(db => db.StringSet(key, json, expiry));        }        /// <summary>        /// 获取单个key的值        /// </summary>        /// <param name="key">Redis Key</param>        /// <returns></returns>        public string StringGet(string key)        {            key = AddSysCustomKey(key);            return Do(db => db.StringGet(key));        }        /// <summary>        /// 获取多个Key        /// </summary>        /// <param name="listKey">Redis Key集合</param>        /// <returns></returns>        public RedisValue[] StringGet(List<string> listKey)        {            List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();            return Do(db => db.StringGet(ConvertRedisKeys(newKeys)));        }        /// <summary>        /// 获取一个key的对象        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public T StringGet<T>(string key)        {            key = AddSysCustomKey(key);            return Do(db => ConvertObj<T>(db.StringGet(key)));        }        /// <summary>        /// 为数字增长val        /// </summary>        /// <param name="key"></param>        /// <param name="val">可以为负</param>        /// <returns>增长后的值</returns>        public double StringIncrement(string key, double val = 1)        {            key = AddSysCustomKey(key);            return Do(db => db.StringIncrement(key, val));        }        /// <summary>        /// 为数字减少val        /// </summary>        /// <param name="key"></param>        /// <param name="val">可以为负</param>        /// <returns>减少后的值</returns>        public double StringDecrement(string key, double val = 1)        {            key = AddSysCustomKey(key);            return Do(db => db.StringDecrement(key, val));        }        #endregion 同步方法        #region 异步方法        /// <summary>        /// 保存单个key value        /// </summary>        /// <param name="key">Redis Key</param>        /// <param name="value">保存的值</param>        /// <param name="expiry">过期时间</param>        /// <returns></returns>        public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?))        {            key = AddSysCustomKey(key);            return await Do(db => db.StringSetAsync(key, value, expiry));        }        /// <summary>        /// 保存多个key value        /// </summary>        /// <param name="keyValues">键值对</param>        /// <returns></returns>        public async Task<bool> StringSetAsync(List<KeyValuePair<RedisKey, RedisValue>> keyValues)        {            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();            return await Do(db => db.StringSetAsync(newkeyValues.ToArray()));        }        /// <summary>        /// 保存一个对象        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="obj"></param>        /// <param name="expiry"></param>        /// <returns></returns>        public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))        {            key = AddSysCustomKey(key);            string json = ConvertJson(obj);            return await Do(db => db.StringSetAsync(key, json, expiry));        }        /// <summary>        /// 获取单个key的值        /// </summary>        /// <param name="key">Redis Key</param>        /// <returns></returns>        public async Task<string> StringGetAsync(string key)        {            key = AddSysCustomKey(key);            return await Do(db => db.StringGetAsync(key));        }        /// <summary>        /// 获取多个Key        /// </summary>        /// <param name="listKey">Redis Key集合</param>        /// <returns></returns>        public async Task<RedisValue[]> StringGetAsync(List<string> listKey)        {            List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();            return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys)));        }        /// <summary>        /// 获取一个key的对象        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public async Task<T> StringGetAsync<T>(string key)        {            key = AddSysCustomKey(key);            string result = await Do(db => db.StringGetAsync(key));            return ConvertObj<T>(result);        }        /// <summary>        /// 为数字增长val        /// </summary>        /// <param name="key"></param>        /// <param name="val">可以为负</param>        /// <returns>增长后的值</returns>        public async Task<double> StringIncrementAsync(string key, double val = 1)        {            key = AddSysCustomKey(key);            return await Do(db => db.StringIncrementAsync(key, val));        }        /// <summary>        /// 为数字减少val        /// </summary>        /// <param name="key"></param>        /// <param name="val">可以为负</param>        /// <returns>减少后的值</returns>        public async Task<double> StringDecrementAsync(string key, double val = 1)        {            key = AddSysCustomKey(key);            return await Do(db => db.StringDecrementAsync(key, val));        }        #endregion 异步方法        #endregion String        #region Hash        #region 同步方法        /// <summary>        /// 判断某个数据是否已经被缓存        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public bool HashExists(string key, string dataKey)        {            key = AddSysCustomKey(key);            return Do(db => db.HashExists(key, dataKey));        }        /// <summary>        /// 存储数据到hash表        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="t"></param>        /// <returns></returns>        public bool HashSet<T>(string key, string dataKey, T t)        {            key = AddSysCustomKey(key);            return Do(db =>            {                string json = ConvertJson(t);                return db.HashSet(key, dataKey, json);            });        }        /// <summary>        /// 移除hash中的某值        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public bool HashDelete(string key, string dataKey)        {            key = AddSysCustomKey(key);            return Do(db => db.HashDelete(key, dataKey));        }        /// <summary>        /// 移除hash中的多个值        /// </summary>        /// <param name="key"></param>        /// <param name="dataKeys"></param>        /// <returns></returns>        public long HashDelete(string key, List<RedisValue> dataKeys)        {            key = AddSysCustomKey(key);            //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};            return Do(db => db.HashDelete(key, dataKeys.ToArray()));        }        /// <summary>        /// 从hash表获取数据        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public T HashGet<T>(string key, string dataKey)        {            key = AddSysCustomKey(key);            return Do(db =>            {                string value =http://www.mamicode.com/ db.HashGet(key, dataKey);                return ConvertObj<T>(value);            });        }        /// <summary>        /// 为数字增长val        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="val">可以为负</param>        /// <returns>增长后的值</returns>        public double HashIncrement(string key, string dataKey, double val = 1)        {            key = AddSysCustomKey(key);            return Do(db => db.HashIncrement(key, dataKey, val));        }        /// <summary>        /// 为数字减少val        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="val">可以为负</param>        /// <returns>减少后的值</returns>        public double HashDecrement(string key, string dataKey, double val = 1)        {            key = AddSysCustomKey(key);            return Do(db => db.HashDecrement(key, dataKey, val));        }        /// <summary>        /// 获取hashkey所有Redis key        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public List<T> HashKeys<T>(string key)        {            key = AddSysCustomKey(key);            return Do(db =>            {                RedisValue[] values = db.HashKeys(key);                return ConvetList<T>(values);            });        }        #endregion 同步方法        #region 异步方法        /// <summary>        /// 判断某个数据是否已经被缓存        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public async Task<bool> HashExistsAsync(string key, string dataKey)        {            key = AddSysCustomKey(key);            return await Do(db => db.HashExistsAsync(key, dataKey));        }        /// <summary>        /// 存储数据到hash表        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="t"></param>        /// <returns></returns>        public async Task<bool> HashSetAsync<T>(string key, string dataKey, T t)        {            key = AddSysCustomKey(key);            return await Do(db =>            {                string json = ConvertJson(t);                return db.HashSetAsync(key, dataKey, json);            });        }        /// <summary>        /// 移除hash中的某值        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public async Task<bool> HashDeleteAsync(string key, string dataKey)        {            key = AddSysCustomKey(key);            return await Do(db => db.HashDeleteAsync(key, dataKey));        }        /// <summary>        /// 移除hash中的多个值        /// </summary>        /// <param name="key"></param>        /// <param name="dataKeys"></param>        /// <returns></returns>        public async Task<long> HashDeleteAsync(string key, List<RedisValue> dataKeys)        {            key = AddSysCustomKey(key);            //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};            return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray()));        }        /// <summary>        /// 从hash表获取数据        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <returns></returns>        public async Task<T> HashGeAsync<T>(string key, string dataKey)        {            key = AddSysCustomKey(key);            string value = http://www.mamicode.com/await Do(db => db.HashGetAsync(key, dataKey));            return ConvertObj<T>(value);        }        /// <summary>        /// 为数字增长val        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="val">可以为负</param>        /// <returns>增长后的值</returns>        public async Task<double> HashIncrementAsync(string key, string dataKey, double val = 1)        {            key = AddSysCustomKey(key);            return await Do(db => db.HashIncrementAsync(key, dataKey, val));        }        /// <summary>        /// 为数字减少val        /// </summary>        /// <param name="key"></param>        /// <param name="dataKey"></param>        /// <param name="val">可以为负</param>        /// <returns>减少后的值</returns>        public async Task<double> HashDecrementAsync(string key, string dataKey, double val = 1)        {            key = AddSysCustomKey(key);            return await Do(db => db.HashDecrementAsync(key, dataKey, val));        }        /// <summary>        /// 获取hashkey所有Redis key        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public async Task<List<T>> HashKeysAsync<T>(string key)        {            key = AddSysCustomKey(key);            RedisValue[] values = await Do(db => db.HashKeysAsync(key));            return ConvetList<T>(values);        }        #endregion 异步方法        #endregion Hash        #region List        #region 同步方法        /// <summary>        /// 移除指定ListId的内部List的值        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public void ListRemove<T>(string key, T value)        {            key = AddSysCustomKey(key);            Do(db => db.ListRemove(key, ConvertJson(value)));        }        /// <summary>        /// 获取指定key的List        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public List<T> ListRange<T>(string key)        {            key = AddSysCustomKey(key);            return Do(redis =>            {                var values = redis.ListRange(key);                return ConvetList<T>(values);            });        }        /// <summary>        /// 入队        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public void ListRightPush<T>(string key, T value)        {            key = AddSysCustomKey(key);            Do(db => db.ListRightPush(key, ConvertJson(value)));        }        /// <summary>        /// 出队        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public T ListRightPop<T>(string key)        {            key = AddSysCustomKey(key);            return Do(db =>             {                 var value =http://www.mamicode.com/ db.ListRightPop(key);                 return ConvertObj<T>(value);             });        }        /// <summary>        /// 入栈        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="value"></param>        public void ListLeftPush<T>(string key, T value)        {            key = AddSysCustomKey(key);            Do(db => db.ListLeftPush(key, ConvertJson(value)));        }        /// <summary>        /// 出栈        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public T ListLeftPop<T>(string key)        {            key = AddSysCustomKey(key);            return Do(db =>            {                var value =http://www.mamicode.com/ db.ListLeftPop(key);                return ConvertObj<T>(value);            });        }        /// <summary>        /// 获取集合中的数量        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public long ListLength(string key)        {            key = AddSysCustomKey(key);            return Do(redis => redis.ListLength(key));        }        #endregion 同步方法        #region 异步方法        /// <summary>        /// 移除指定ListId的内部List的值        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public async Task<long> ListRemoveAsync<T>(string key, T value)        {            key = AddSysCustomKey(key);            return await Do(db => db.ListRemoveAsync(key, ConvertJson(value)));        }        /// <summary>        /// 获取指定key的List        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public async Task<List<T>> ListRangeAsync<T>(string key)        {            key = AddSysCustomKey(key);            var values = await Do(redis => redis.ListRangeAsync(key));            return ConvetList<T>(values);        }        /// <summary>        /// 入队        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public async Task<long> ListRightPushAsync<T>(string key, T value)        {            key = AddSysCustomKey(key);            return await Do(db => db.ListRightPushAsync(key, ConvertJson(value)));        }        /// <summary>        /// 出队        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public async Task<T> ListRightPopAsync<T>(string key)        {            key = AddSysCustomKey(key);            var value = http://www.mamicode.com/await Do(db => db.ListRightPopAsync(key));            return ConvertObj<T>(value);        }        /// <summary>        /// 入栈        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <param name="value"></param>        public async Task<long> ListLeftPushAsync<T>(string key, T value)        {            key = AddSysCustomKey(key);            return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value)));        }        /// <summary>        /// 出栈        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="key"></param>        /// <returns></returns>        public async Task<T> ListLeftPopAsync<T>(string key)        {            key = AddSysCustomKey(key);            var value = http://www.mamicode.com/await Do(db => db.ListLeftPopAsync(key));            return ConvertObj<T>(value);        }        /// <summary>        /// 获取集合中的数量        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public async Task<long> ListLengthAsync(string key)        {            key = AddSysCustomKey(key);            return await Do(redis => redis.ListLengthAsync(key));        }        #endregion 异步方法        #endregion List        #region SortedSet 有序集合        #region 同步方法        /// <summary>        /// 添加        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <param name="score"></param>        public bool SortedSetAdd<T>(string key, T value, double score)        {            key = AddSysCustomKey(key);            return Do(redis => redis.SortedSetAdd(key, ConvertJson<T>(value), score));        }        /// <summary>        /// 删除        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public bool SortedSetRemove<T>(string key, T value)        {            key = AddSysCustomKey(key);            return Do(redis => redis.SortedSetRemove(key, ConvertJson(value)));        }        /// <summary>        /// 获取全部        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public List<T> SortedSetRangeByRank<T>(string key)        {            key = AddSysCustomKey(key);            return Do(redis =>            {                var values = redis.SortedSetRangeByRank(key);                return ConvetList<T>(values);            });        }        /// <summary>        /// 获取集合中的数量        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public long SortedSetLength(string key)        {            key = AddSysCustomKey(key);            return Do(redis => redis.SortedSetLength(key));        }        #endregion 同步方法        #region 异步方法        /// <summary>        /// 添加        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <param name="score"></param>        public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score)        {            key = AddSysCustomKey(key);            return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson<T>(value), score));        }        /// <summary>        /// 删除        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        public async Task<bool> SortedSetRemoveAsync<T>(string key, T value)        {            key = AddSysCustomKey(key);            return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value)));        }        /// <summary>        /// 获取全部        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public async Task<List<T>> SortedSetRangeByRankAsync<T>(string key)        {            key = AddSysCustomKey(key);            var values = await Do(redis => redis.SortedSetRangeByRankAsync(key));            return ConvetList<T>(values);        }        /// <summary>        /// 获取集合中的数量        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public async Task<long> SortedSetLengthAsync(string key)        {            key = AddSysCustomKey(key);            return await Do(redis => redis.SortedSetLengthAsync(key));        }        #endregion 异步方法        #endregion SortedSet 有序集合        #region key        /// <summary>        /// 删除单个key        /// </summary>        /// <param name="key">redis key</param>        /// <returns>是否删除成功</returns>        public bool KeyDelete(string key)        {            key = AddSysCustomKey(key);            return Do(db => db.KeyDelete(key));        }        /// <summary>        /// 删除多个key        /// </summary>        /// <param name="keys">rediskey</param>        /// <returns>成功删除的个数</returns>        public long KeyDelete(List<string> keys)        {            List<string> newKeys = keys.Select(AddSysCustomKey).ToList();            return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys)));        }        /// <summary>        /// 判断key是否存储        /// </summary>        /// <param name="key">redis key</param>        /// <returns></returns>        public bool KeyExists(string key)        {            key = AddSysCustomKey(key);            return Do(db => db.KeyExists(key));        }        /// <summary>        /// 重新命名key        /// </summary>        /// <param name="key">就的redis key</param>        /// <param name="newKey">新的redis key</param>        /// <returns></returns>        public bool KeyRename(string key, string newKey)        {            key = AddSysCustomKey(key);            return Do(db => db.KeyRename(key, newKey));        }        /// <summary>        /// 设置Key的时间        /// </summary>        /// <param name="key">redis key</param>        /// <param name="expiry"></param>        /// <returns></returns>        public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?))        {            key = AddSysCustomKey(key);            return Do(db => db.KeyExpire(key, expiry));        }        #endregion key        #region 发布订阅        /// <summary>        /// Redis发布订阅  订阅        /// </summary>        /// <param name="subChannel"></param>        /// <param name="handler"></param>        public void Subscribe(string subChannel, Action<RedisChannel, RedisValue> handler = null)        {            ISubscriber sub = _conn.GetSubscriber();            sub.Subscribe(subChannel, (channel, message) =>            {                if (handler == null)                {                    Console.WriteLine(subChannel + " 订阅收到消息:" + message);                }                else                {                    handler(channel, message);                }            });        }        /// <summary>        /// Redis发布订阅  发布        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="channel"></param>        /// <param name="msg"></param>        /// <returns></returns>        public long Publish<T>(string channel, T msg)        {            ISubscriber sub = _conn.GetSubscriber();            return sub.Publish(channel, ConvertJson(msg));        }        /// <summary>        /// Redis发布订阅  取消订阅        /// </summary>        /// <param name="channel"></param>        public void Unsubscribe(string channel)        {            ISubscriber sub = _conn.GetSubscriber();            sub.Unsubscribe(channel);        }        /// <summary>        /// Redis发布订阅  取消全部订阅        /// </summary>        public void UnsubscribeAll()        {            ISubscriber sub = _conn.GetSubscriber();            sub.UnsubscribeAll();        }        #endregion 发布订阅        #region 其他        public ITransaction CreateTransaction()        {            return GetDatabase().CreateTransaction();        }        public IDatabase GetDatabase()        {            return _conn.GetDatabase(DbNum);        }        public IServer GetServer(string hostAndPort)        {            return _conn.GetServer(hostAndPort);        }        /// <summary>        /// 设置前缀        /// </summary>        /// <param name="customKey"></param>        public void SetSysCustomKey(string customKey)        {            CustomKey = customKey;        }        #endregion 其他        #region 辅助方法        private string AddSysCustomKey(string oldKey)        {            var prefixKey = CustomKey ?? RedisConnectionHelp.SysCustomKey;            return prefixKey + oldKey;        }        private T Do<T>(Func<IDatabase, T> func)        {            var database = _conn.GetDatabase(DbNum);            return func(database);        }        private string ConvertJson<T>(T value)        {            string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value);            return result;        }        private T ConvertObj<T>(RedisValue value)        {            return JsonConvert.DeserializeObject<T>(value);        }        private List<T> ConvetList<T>(RedisValue[] values)        {            List<T> result = new List<T>();            foreach (var item in values)            {                var model = ConvertObj<T>(item);                result.Add(model);            }            return result;        }        private RedisKey[] ConvertRedisKeys(List<string> redisKeys)        {            return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray();        }        #endregion 辅助方法    }
RedisHelper

 下面是CookieHelper   cookie的读写操作

技术分享
 public class CookieHelper    {        //sessionId 的Key        const string RedisSessionCookiesId = "RedisSessionCookiesId";        /// <summary>        /// 获取设置SessionID值        /// </summary>        /// <returns></returns>        public static string CreatSessionCookie()        {            if (HttpContext.Current.Request.Cookies[RedisSessionCookiesId] != null)            {                return HttpContext.Current.Request.Cookies[RedisSessionCookiesId].Value.ToString();            }            else            {                Guid guid = Guid.NewGuid();                HttpCookie cokie = new HttpCookie(RedisSessionCookiesId);                cokie.Value = guid.ToString();                cokie.Expires = System.DateTime.Now.AddDays(0.5);                cokie.Domain = "localhost";                cokie.HttpOnly = true;                HttpContext.Current.Response.Cookies.Add(cokie);                return guid.ToString();            }        }    }
CookieHelper

 SessionHelper 构建rediskey value 写入以及读取

技术分享
 public class SessionHelper    {        public string this[string key]        {            get            {                RedisHelper Redis = new RedisHelper(0);                key = CookieHelper.CreatSessionCookie() + "_" + key;                return Redis.StringGet(key);            }            set            {                SetSession(key, value);            }        }        public void SetSession(string key, string value)        {            if (string.IsNullOrWhiteSpace(key))            {                throw new Exception("Key is Null or Epmty");            }            RedisHelper Redis = new RedisHelper(0);            key = CookieHelper.CreatSessionCookie() + "_" + key;            Redis.StringSet(key, value, TimeSpan.FromSeconds(200000));        }        public string SessionId        {            get { return CookieHelper.CreatSessionCookie(); }        }    }
SessionHelper

 Test.Console 主要是一些redis的操作示例 感兴趣的可以自己尝试下

然后看下 SessionManagerDemo的Web.config,主要添加两个地方

<connectionStrings>    <add name="RedisExchangeHosts" connectionString="localhost:6379,allowadmin=true" />    <!-- 如设置密码  ,password=******-->  </connectionStrings>
<appSettings>    <add key="redisKey" value="http://www.mamicode.com/WeiXin:Openid" /></appSettings>

OK! 先简单运行下  SessionManagerDemo的Default.aspx 

我们这里用了自己本地windows版本的redis,然后用 RedisDesktopManager看运行结果是否写入到redis

技术分享页面展示没问题,看看浏览器是否写入cookie

技术分享

可以看到 key value domain 过期时间都设置成功,看下RedisDesktopManager

技术分享

OK,也是成功的

接下来我们把session写入的操作注释掉在运行

  // sessionHelper["test123"] = "session 共享测试!";

技术分享技术分享

两个都没有问题,嗯,结果还可以!

接下来,我们要借用nginx来测试测试

 

Nginx+IIS+Redis 处理Session共享问题 1