1 Overview
Session
的作用是什么呢?我们都知道 Http
协议是无状态的,也就是说每次 Http
请求都是独立的,它们之间不会知道彼此之间的联系。而 Session
的机制可以让 Http
请求存在相关性。
那么在 Asp.NET Core
应用程序使用 Session
呢?
Services.AddDistributedMemoryCache()
表明使用分布式内存作为Session
存储的位置Service.AddSession()
设置Session
的信息,比如有效时间是 10 秒钟,客户端的Cookie
信息app.UseSession
开始使用Session
这个中间件.
当注册完 Session
中间件后, 就可以在 Controller
使用 HttpContext.Session
来进行操作。上面的例子中,在访问 https://example.com/
的时候,设置了 Session
中 Name
和 Age
两个字段,如果浏览器紧接着访问 https://example.com/about
时候,我们在页面上仍然看到之前的配置。通过这种方式,在一段时间内保存了 Http
请求之间的关联性。
Session
的数据流是这样的
- 客户端的浏览器带着
Cookie
来访问服务器,其中.AspNetCore.Sesion=foobar
是Session
中间件关系的Cookie
- 根据
foobar
作为SessionKey
去后端的存储的地方通过load
拿到Session
,如果没有或者expired
了,这创建这个Session
对象,并且将这个Session
作为HttpContext
的一个Feature
以便在HttpContext
中使用 - 当
Session
这个中间件执行完毕,调用Commit
方法,将处理后的数据,保存到后端的存储中
2. SessionOptions
CookieBuilder Cookie
可以Build
生成CookieOptions
, 在这其中有一些默认值IdleTimeout
:Session
的有效时间IOTimeOut
:Session
在存取的超时时间
3. ISessionStore/DistributedSessionStore
ISessionStore
是 Session
的存储层,这个接口的 API
的定义如下
ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey);
这个返回返回一个 ISession
对象,不管这个 Session
是新建的还是已有的。
DistributedSessionStore
是其中的默认实现。 Create
方法回一个 DistributedSession
实现。
DistributedSession
分布式缓存数据保存和读取是由 IDistributedCache
这个接口完成,而内存中以 Dictionary<EncodedKey, byte[]>
形式存在。也即是说, Session
以字段的形式存在,Key 为字符串,Value 则是字节数组,所以可以是任何形式。
ISession
所有的操作都会委托给 Dictionary<EncodedKey, byte[]>
处理。
由于 IDistributedCache
的读取和写入的时候, key
为字符串, value
也是字符串。由于我们 sessionKey
只有一个,所以涉及到下面的
Deserialize: byte[] -> Dictionary<EncodedKey, byte[]>
Serialize: Dictionary<EncodedKey, byte[]> -> byte[]
它们之间的协议是这样的
- 版本号: 1 byte
- 记录数目: 3 bytes
- SessionId: 16 bytes
- 对于每个记录
- key length: 2 bytes
- key : n bytes
- value length: 4 bytes
- value: n bytes
4. SessionMiddleware
SessionMiddleware
的 Invoke
方法如下
Cookie
中没有包含 Session key
或者是不合法的 Session Key
, 需要创建一个新的 Session key
- 分配一个 16 字节的数组,并且随机填充
- 然后通过
_dataProtector
来加密存放到cookie
中的值 - 然后通过
SessionEstablisher
来注册Response
开始的时候,往header
中cookie
写入数据,比如这里的Session key
在有了合法的 Session key
之后,
- 通过
Create
方法创建与一个ISession
对象, - 将它赋值给
HttpFeatures
中的ISessionFeature
- 后续的中间件可以通过
HttpContext.Session
来获得创建的ISession
对象
在后续的中间件处理完毕之后,需要将 Session
执行 CommitAsync
方法,来保存获取或者修改后的 Session
对象。