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 = )
: 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 = )
{
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 = )
{
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 = )
{
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 = )
{
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 = 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 = )
{
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 = )
{
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 = 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 = )
{
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 = )
{
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 = 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 = 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 = 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 = 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();
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(); key = CookieHelper.CreatSessionCookie() + "_" + key;
Redis.StringSet(key, value, TimeSpan.FromSeconds());
}
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="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的更多相关文章
- Nginx+IIS+Redis 处理Session共享问题 2
接下来主要说下利用nginx来测试 两台Windows server 1.10.120.131.210 - 端口84部署demo 2.10.120.131.211 - 端口84部署demo ngi ...
- nginx+tpmcat+redis实现session共享
nginx+tpmcat+redis实现session共享 版本:nginx nginx-1.8.0.tar.gztomcat apache-tomcat-7.0.78.tar.gzredis re ...
- Nginx+tomcat+redis实现session共享
Nginx+tomcat+redis实现session共享 1,安装nginx,使用yum -y install nginx 这是epel源中的,需要安装epel源. 2,配置nginx. 在ngin ...
- nginx+tomcat+redis完成session共享(转载)
转载:http://blog.csdn.net/grhlove123/article/details/48047735 tomcat7下基于redis的session共享所需jar包: http:// ...
- nginx+tomcat+redis完成session共享
本文记录nginx+redis+tomcat实现session共享的过程 nginx安装:http://blog.csdn.net/grhlove123/article/details/4783467 ...
- nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...
- nginx+tomcat实现集群,redis实现session共享,软连接实现文件共享:http://blog.csdn.net/hua1586981/article/details/78132710
转载 2017年02月08日 16:52:41 730 相信很多人都听过nginx,这个小巧的东西慢慢地在吞食apache和IIS的份额.那究竟它有什么作用呢?可能很多人未必了解. 说到反向代理,可能 ...
- Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享
Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 ============================= 蕃薯耀 2017年11月27日 http: ...
- Nginx+Tomcat搭建集群,Spring Session+Redis实现Session共享
小伙伴们好久不见!最近略忙,博客写的有点少,嗯,要加把劲.OK,今天给大家带来一个JavaWeb中常用的架构搭建,即Nginx+Tomcat搭建服务集群,然后通过Spring Session+Redi ...
随机推荐
- javascript设计模式之解释器模式详解
http://www.jb51.net/article/50680.htm 神马是“解释器模式”? 先翻开<GOF>看看Definition:给定一个语言,定义它的文法的一种表示,并定义一 ...
- Quercus
其实,我不确定Quercus是否可以被认定为一门JVM语言:其次Quercus这个东东分开源版与商业版,开源版只能解释执行.而商业版能编译成Java字节码. 但我知道国内,阿里巴巴很早就在使用它,当然 ...
- JSP 禁用脚本设置
JSP 禁用脚本设置: web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app xm ...
- MyBatis 一级、二级缓存
一级 默认session就有一级缓存,session有C/U/D操作或者session.clearCache();session.commit();都会清空缓存: 二级在mapper.xml中添加&l ...
- easyUI 初始化的两种方式
easyUI 初始化的两种方式: class方式和js方式: <!DOCTYPE html> <html lang="en"> <head> & ...
- 转:Oracle弃用sun.reflect.Reflection.getCallerClass
http://www.infoq.com/cn/news/2013/07/Oracle-Removes-getCallerClass 作为Java开发者,我们经常忽略@Deprecated注释,继续使 ...
- 使用fullPage.js遇到的问题以及翻译
使用fullPage.js做一简单页面,遇一古怪问题:.section中的h1标签始终被一插件生成的标签包裹,导致样式调整好不困难!花费数小时排查为何会生成这样一个标签,最终在fullPage.js的 ...
- GIS制图课程目录
由于更新次序跳跃式更新,因此很有必要整理一下全书目录,并将会按照实际学习的顺序进行更新. [前言] GIS制图课程前言 [理论篇] 理论篇-地图学与GIS制图的基础理论(一) 理论篇-地图学与GIS制 ...
- Asp.net mvc 知多少(七)
本系列主要翻译自<ASP.NET MVC Interview Questions and Answers >- By Shailendra Chauhan,想看英文原版的可访问http:/ ...
- poj1611
The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 35918 Accepted: 17458 De ...