簡體   English   中英

添加了 HttpContext.Session 中缺少的鍵(並發)

[英]Added keys missing from HttpContext.Session (concurrency)

我正在使用.NET Core 3.1 我想知道HttpContext.Session.SetString(...)是否是線程安全的 例如,客戶端同時向同一個 controller 操作( Test )發出兩個請求。 Controller 將字符串添加到 session(參見下面的示例)。 最后 session 中是否會有兩個、一個或零鍵(例如,當我刷新頁面時)?

public IActionResult Test()
{
    HttpContext.Session.SetString(Guid.NewGuid().ToString(), "test");
    return Ok();
}

使用DevExtreme FileUploader時,我將一些值保存到 session 。 當我一次上傳多個文件時,組件同時發出多個請求,最后, session 通常缺少一些鍵 我認為有一些比賽條件正在發生。

添加:客戶代碼

我注意到 session 鍵僅在我使用method: 'POST' (只有 1 個鍵)。 如果我使用method: 'GET' ,則有 3 個鍵(正確)。

$(document).ready(function () {
    var method = 'GET'; // works (3 keys)
    //var method = 'POST'; // doesn't work (1 key)

    $('#fire').on('click', function () {
        $.when(
            $.ajax({
                url: 'Session/Test',
                method: method,
                success: function(){
                    console.log('response', 1);
                }
            }),

            $.ajax({
                url: 'Session/Test',
                method: method,
                success: function(){
                    console.log('response', 2);
                }
            }),

            $.ajax({
                url: 'Session/Test',
                method: method,
                success: function(){
                    console.log('response', 3);
                }
            })
        ).then(function () {
            alert('Done');
        });
    });
});

假設您使用 ASP.Net Core 提供的默認 session 實現。

HttpContext.Session而言:

HttpContext.Session返回一個DistributedSession的實例,它在內部使用Dictionary<TKey, TValaue> 字典不是線程安全的,因此如果您從多個線程(例如Task.Run )訪問Session ,可能會導致意外結果。

對於不同請求的 Session 而言:

在 ASP.Net Core 中, Session來自ISessionStore ,它具有短暫的生命周期 意思是,請求不共享Session object 所以如果你有並發請求,每個請求都有自己的Session object。

在比賽條件方面:

The default implementation of session reads/writes session state from/to .AspNetCore.Session cookie. 可能會導致競爭條件。

因為Session是每個客戶端的,所以當您有來自同一客戶端的並發請求觸及同一 cookie 中的相同位和部分時,您可能會遇到競爭條件 / session state 然而,競爭條件不是因為服務器端的Session 它實際上是由客戶端的 cookie 管理引起的。

Session state 是非鎖定的。 如果兩個請求同時嘗試修改 session 的內容,則最后一個請求將覆蓋第一個請求。

考慮這個例子:

Say you have a controller action which sets Session with provided value , and another controller action retrieves the value from Session and returns it in body:

[HttpGet]
[Route("create")]
public IActionResult CreateSession([FromQuery]string value)
{
    HttpContext.Session.SetString("key", value);
    return Ok();
}

[HttpGet]
[Route("get")]
public IActionResult ReturnSession([FromQuery] string expected)
{
    var actual = HttpContext.Session.GetString("key");
    return Ok(new { actual, expected });
}

如果您使用HttpClient測試這些操作:

async Task TestSession(HttpClient client, string str)
{
    await client.GetAsync($"https://localhost:5001/session/create?value={str}");
    var r = await client.GetAsync($"https://localhost:5001/session/get?expected={str}");
    var session = await r.Content.ReadAsStringAsync();

    Console.WriteLine(session);
}

using (var client = new HttpClient())
{
    await TestSession(client, "abc");
}

output 應如下所示:

{"actual":"abc","expected":"abc"}

當您有來自同一客戶端的並發請求時會出現問題:

using (var client = new HttpClient())
{
    var tasks = new List<Task>();
    for (var i = 0; i < 10; i++)
    {
        var str = i.ToString();
        tasks.Add(Task.Run(() => TestSession(client, str)));
    }

    await Task.WhenAll(tasks);
}

output 看起來像:

{"actual":"2","expected":"1"}
{"actual":"3","expected":"6"}
{"actual":"4","expected":"5"}
{"actual":"4","expected":"3"}
{"actual":"4","expected":"2"}
{"actual":"8","expected":"4"}
{"actual":"7","expected":"8"}
{"actual":"7","expected":"7"}
{"actual":"9","expected":"0"}
{"actual":"9","expected":"9"}

In the above case, session state was changed by request 3 , between create and get of request 6 , meaning it is likely request 6 cannot see its session state correctly.

為避免此問題,您可以為每個批次使用不同的HttpClient

不,dotnet collections 不是線程安全的,session 也不是。 如果您在多個線程上共享相同的 session,則應將其視為只讀

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM