一. 概述
HTTP 是无状态的协议. 默认情况下, HTTP 请求是不保留用户值或应用状态的独立消息. 本文介绍了几种保留请求间用户数据和应用状态的方法. 下面以表格形式列出这些存储方式, 本篇专讲 Session 会话状态, 计划下篇再讲应用状态.
存储方法 | 存储机制 |
Cookie | HTTP Cookie(可能包括使用服务器端应用代码存储的数据) |
Session 状态 | HTTP Cookie 和服务器端应用代码 |
TempData | HTTP Cookie 或 Session 状态 |
查询字符串 | HTTP 查询字符串 |
隐藏字段 | HTTP 窗体字段 |
HttpContext.Items | 服务器端应用代码 |
Cache | 服务器端应用代码 |
依赖关系注入 | 服务器端应用代码 |
1.1 Cookie
Cookie 是服务器产生 ID 的标签. 是识别用户, 实现持久会话的最好方式. Cookie 分为两类: 会话 Cookie 和持久 Cookie. 二者唯一区别是设置过期时间.
(1)会话 Cookie 是临时的, 当用户退出浏览器时, 就会被删除.
(2)持久 Cookie 生存时间更长, 存储在硬盘上, 当浏览器退出或计算机重启时它们仍然存在.
Cookie 跨请求存储数据, 每次请求都会发送 Cookie.Cookie 的大小应该保持在最低限度. 理想情况下, 仅标识符存储在 Cookie 中. 大多数浏览器 Cookie 大小限制为 4096 个字节. 每个域仅有有限数量的 Cookie 可用, 比如 IE6.0 每个域 cookie 个数最多为 20 个.
下面看 Cookie 是如何工作的:
(a) 客户端首次 Request 请求 web 站点时, Web 服务器对客户端一无所知.
(b) Web 服务器通过 Response 报文的 Set-Cookie 或 Set-Cookie2 产生标识 Cookie id="34294", 返回给客户端, 客户端浏览器会存储该 Cookie.
(c) 当客户端再次 Request 请求时, 带上 Cookie,Web 服务器就能识别该客户端, 实现会话.
1.2 Session (会话)介绍
Session 数据由缓存支持并被视为临时数据, Session 状态是用户浏览 Web 应用程序时, 存储用户数据的 ASP.NET Core 方案. Session 状态使用应用维护的存储, 来保存客户端所有请求的数据. ASP.NET Core 通过向客户端提供包含 Session ID 的 cookie 来维护 Session 状态, 该 Session ID 随每个请求一起发送到应用程序(Web 服务器). 该应用程序使用 Session ID 来获取 Session 数据(Session 数据存储在 Web 服务器上).Session 会话状态以下主要行为:
(1) 由于 cookie Session 是特定于浏览器的, 因此不能跨浏览器共享会话.
(2) 应用在上次请求后保留 Session 的时间有限. 应用程序可以设置 Session 超时, 或者使用 20 分钟的默认值.
(3) 建议不使用粘性会话, 更好的方法是使用 Redis 或 SQL Server 分布式缓存, 它不需要粘性会话.
1.3 Session 会话选项
若要替代 Session 默认值, 使用 SessionOptions (services.AddSession). 下面是主要选项, 以及示例:
选项 | 说明 |
Cookie | 确定用于创建 Cookie 的设置。名称默认为. AspNetCore.Session |
IdleTimeout | 空闲多长时间 Session 重置。 此设置仅适用于 Session 内容,不适用于 Cookie。 默认为 20 分钟。 |
IOTimeout | 允许从存储加载会话或者将其提交回存储的最大时长。 此设置可能仅适用于异步操作。 可以使用 InfiniteTimeSpan 禁用超时。 默认值为 1 分钟 |
- // 选项配置
- services.AddSession(options =>
- {
- options.Cookie.Name = ".AdventureWorks.Session";
- options.IdleTimeout = TimeSpan.FromSeconds(10);
- });
1.4 Session 设置和获取值
在 Microsoft.AspNetCore.Session 包中提供中间件来管理 Session 状态. 若要启用 Session 中间件, Startup 必须包含如下:
(1) 任何 IDistributedCache 内存缓存. 该 IDistributedCache 实现用作 Session 的后备存储, 下面会讲到分布式缓存在 ASP.NET Core 中.
(2) 对 ConfigureServices 方法中 AddSession 的调用.
(3) 对 Configure 中 UseSession(); 的调用.
二. Session 存储 in memory
在 ASP.NET Core 中, 分布式缓存无论使用 in memory,SQL Server,Redis 都需要应用程序使用 IDistributedCache 接口与缓存进行交互. Session 存储在 in memory 中, 称为 "分布式内存缓存"(AddDistributedMemoryCache). 是框架提供的 IDistributedCache 实现. 注意: 分布式内存缓存不是实际的分布式缓存, 该缓存是存储在运行应用程序的服务器上.
运用场景一般用在开发或测试中. 也可以用在生产环境下, 但必须是内存消耗不高并且应用程序是单个节点(没有 Web 分发负载).
2.1 Startup 文件配置 session
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- //..
- services.AddDistributedMemoryCache();
- services.AddHttpContextAccessor();
- services.AddSession(options =>
- {
- // 空闲 10 秒后, session 自动清空
- options.IdleTimeout = TimeSpan.FromSeconds(10);
- options.Cookie.HttpOnly = true;
- });
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
- }
- public void Configure(IApplicationBuilder App, IHostingEnvironment env)
- {
- //..
- // 顺序很重要, 必须放在 UseMvc 之前. 配置后 HttpContext.Session 可用
- App.UseSession();
- App.UseMvc();
- }
- }
2.2 使用属性 HttpContext.Session 从 Razor Pages PageModel 类或 MVC 控制器类访问会话状态.
- public class HomeController : Controller
- {
- private readonly IHttpContextAccessor _accessor;
- public HomeController( IHttpContextAccessor httpContextAccessor)
- {
- this._accessor = httpContextAccessor;
- }
- public IActionResult Index()
- {
- HttpContext.Session.SetString("SessionTest", "Ben Rules!");
- return View();
- }
- public IActionResult Privacy()
- {
- ViewData["SessionTest"] = _accessor.HttpContext.Session.GetString("SessionTest");
- return View();
- }
- }
先运行 index 页设置 Session 后, 再运行 Privacy 页读取该 Session. 如下图: Session 会话设置和获取值成功, 再查看浏览器中的 Cookies 名称默认为. AspNetCore.Session.
2.3 Session 数据序列化
必须对所有 Session 数据进行序列化以启用分布式缓存方案, 即使是在使用 in memory 缓存的时候. 对于字符串和数据序列化以由 ISession 扩展方法实现了. 对于复杂类型, 添加以下扩展方法以设置和获取可序列化的对象.
- public static class SessionExtensions
- {
- public static void Set<T>(this ISession session, string key, T value)
- {
- session.SetString(key, JsonConvert.SerializeObject(value));
- }
- public static T Get<T>(this ISession session, string key)
- {
- var value = session.GetString(key);
- return value == null ? default(T) :
- JsonConvert.DeserializeObject<T>(value);
- }
- }
- // 以下示例演示如何使用扩展方法设置和获取可序列化的对象:
- HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
三. Session 存储 Redis
Redis 缓存比 SQL Server 缓存提供更高的吞吐量和更低的延迟. 这里不在演示 SQL Server 存储, 如果要用 SQL Serverd 存储, 建议为分布式缓存提供专用的 SQL Server 实例(与应用程序的数据库实例分开).
3.1 Redis 服务器
关于 Redis 的安装, 这里不在介绍.
- # 启动 Redis 服务成功
- [root@localhost bin]# ./Redis-server Redis.conf
- # 启动 Redis 客户端测试成功
- [root@localhost bin]# ./Redis-cli -h 172.168.18.200 -a 123456
- 127.0.0.1:6379> set msg "hello"
- OK
- 127.0.0.1:6379> get msg
- "hello"
3.2 ASP.NET core 应用端
(1)演示项目是基于上面的 in memory 案例, 先安装 Redis 中间件.
PM> Install-Package Microsoft.Extensions.Caching.Redis
(2)将 in memory 改为 Redis 存储, 代码改动如下:
- //services.AddDistributedMemoryCache();
- services.AddDistributedRedisCache(options =>
- {
- options.Configuration = "172.168.18.200:6379,allowAdmin=true,password=123456,defaultdatabase=0";
- });
- services.AddHttpContextAccessor();
- services.AddSession(options =>
- {
- options.IdleTimeout = TimeSpan.FromSeconds(10);
- options.Cookie.HttpOnly = true;
- });
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
(3)设置和获取 Session
在 HomeController 类中, 设置和获取 Session, 代码不变, 可参考上面 2.2. 运行 index 页后, 再运行 Privacy 页, Session 会话设置和获取值成功, 再使用 Redis 工具查看已存储到了 Redis 服务中 (空闲 10 秒后, Redis 存储的 session 将自动清空) 如下图所示:
参考资料
ASP.NET Core 中的会话和应用状态
Redis 可视化管理
分布式缓存在 ASP.NET Core 中
来源: https://www.cnblogs.com/MrHSR/p/10544167.html