日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

ASP.NET?Core中間件會話狀態讀寫及生命周期示例_實用技巧

作者:Upgrader ? 更新時間: 2022-06-26 編程語言

前言:

本文使用 .NET Core SDK 3.1 的版本。

1) 關于Http中的會話

  • Http是一種采用請求響應消息交換模式,且無狀態的傳輸協議。
  • 該協議確保客戶端將請求報文發送給目標服務器并接收來自服務端的響應報文,這個報文交換是一個Http事務。
  • 從協議的角度講,即使在使用長連接的情況下,同一個客戶端和服務器之間進行多個Http事務也是完全獨立的
  • 所以需要在應用層為兩者去建立一個上下文來保存多次消息交換的狀態,這就是所謂的會話。

2) 關于 ASP.NET Core 中的會話

  • 在 ASP.NET Core 中利用一個叫做 Session 的中間件來實現會話,
  • 每個會話都有一個標識SessionKey,但是SessionKey不是唯一標識,是一個數據字典的形式,
  • 將SessionKey保存在服務端,當會話中間件在處理會話的第一個請求的時候,會創建一個SessionKey
  • 并基于它創建一個獨立的數據字典來存儲會話狀態,應用程序設置的會話狀態都是自動保存在當前會話對應的數據字典中的
  • 這個SessionKey最終會以 Cookie 的形式寫入響應并返回給客戶端,
  • 客戶端在每次發起請求的時候都會附加這個 Cookie,從而使我們的應用程序能夠準確定位到當前會話對應的數據字典。

一、配置會話中間件

配置基于內存的分布式緩存服務和會話服務,如需要將緩存放置于數據庫可以參考微軟官方文檔

	public void ConfigureServices(IServiceCollection services)
	{
		// 添加基于內存的緩存服務,以供會話中間件來使用
        collection.AddDistributedMemoryCache();
        // 添加會話
        collection.AddSession();
	}

添加會話中間件

	public void Configure(IApplicationBuilder app)
	{
		// 引入會話中間件
		app.UseSession();
	}

二、會話狀態的讀寫

寫入Session

    ISession session = httpContext.Session;
    var sessionStartTime = DateTime.Now.ToString(CultureInfo.InvariantCulture);
    session.SetString("SessionStartTime", sessionStartTime);

讀取Session

    ISession session = httpContext.Session;
    session.TryGetValue("SessionStartTime", out var value);
    var sessionStartTime = Encoding.UTF8.GetString(value);

獲取SessionId

    ISession session = httpContext.Session;
    session.TryGetValue("SessionStartTime", out var value);
    var sessionStartTime = Encoding.UTF8.GetString(value);

獲取SessionKey

SessionKey 需要通過反射獲取

    ISession session = httpContext.Session;
    var field = typeof(DistributedSession).GetTypeInfo()
        .GetField("_sessionKey", BindingFlags.Instance | BindingFlags.NonPublic);
    var sessionKey = field?.GetValue(session);

三、 示例的生命周期

這里準備了示例的代碼:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/get", async httpContext =>
        {
            ISession session = httpContext.Session;
            string sessionStartTime;
            if (session.TryGetValue("SessionStartTime", out var value))
            {
                sessionStartTime = Encoding.UTF8.GetString(value);
            }
            else
            {
                sessionStartTime = DateTime.Now.ToString(CultureInfo.InvariantCulture);
                session.SetString("SessionStartTime", sessionStartTime);
            }
            var field = typeof(DistributedSession).GetTypeInfo()
                .GetField("_sessionKey", BindingFlags.Instance | BindingFlags.NonPublic);
            var sessionKey = field?.GetValue(session);
            var responseText = $@"
                <html>
                <body>
                    <h1>Get Session</h1>
                    <ul>
                        <li>Session ID:{session.Id}</li>
                        <li>Session Key:{sessionKey}</li>
                        <li>Session Start Time:{sessionStartTime}</li>
                        <li>Current Time:{DateTime.Now:yyyy-MM-dd HH:mm:ss}</li>
                    </ul>
                </body>
                </html>";
            httpContext.Response.ContentType = "text/html";
            await httpContext.Response.WriteAsync(responseText);
        });
    });

清除瀏覽器中的 Cookie,然后刷新頁面進入/get頁面中,可以看到在新的網絡請求中響應標頭多了一個 set-cookie,這個set-cookie是被加密的SessionKey,還具有 httponly 的標簽,以防止Cookie 的值被跨站讀取。

默認請求下 Cookie 采用的路徑是根路徑

然后我們重新刷新頁面,可以看到請求標頭中多出一個 cookie,就是之前的 set-cookie,因為之前緩存被清除以后,第一次刷新標頭多一個 set-cookie,相當于創建一個新的會話,當下一次發起請求就會帶上 cookie。

四、其他

  • SessionId 可以作為會話的唯一標識,但是 SessionKey 不可以
  • 也就是說兩個不同的 Session,肯定具有不同的 SessionId,但是他們有可能共享相同的SessionKey
  • 當會話中間件接收到會話的第一個請求的時候,他會創建兩個不同的 guid,分別表示 SessionKey 和 SessionId
  • 其中 SessionId 將被作為會話狀態的一部分被存儲起來,而 SessionKey 則會以會話的形式返回給客戶端
  • 會話一般都是有有效期的,而會話的有效期基本決定了存儲的會話狀態數據的有效期
  • 默認情況下 ASP.NET Core 應用的會話它所采用的默認過期時間是20分鐘, 默認情況下20分鐘內的任意請求都會將會話的壽命延長再延長
  • 兩次請求的時間超過了有效期,意味著這個會話過期,存儲的會話狀態數據包括 SessionId 也都會被清除
  • 但是請求攜帶的 SessionKey 可能還是原來的 SessionKey
  • 在這種請求下,會話中間件會創建一個新的會話,這個新的會話具有不同的 SessionId,但是整個會話狀態仍然會沿用原來的 SessionKey
  • 所以 SessionKey 不能作為會話的唯一標識,它只代表存儲數據的標識
  • 會話本質上就是在應用的層面上提供了一個數據容器來保存客戶端的狀態,這個客戶端狀態就是會話狀態,會話的核心功能就是會話狀態的讀寫

原文鏈接:https://blog.csdn.net/Upgrader/article/details/114271949

欄目分類
最近更新