ASP.NET:Session.SessionID在请求之间发生变化

149

为什么在ASP.NET页面中,Session对象上的SessionID属性会在请求之间发生变化?

我有一个类似这样的页面:

...
<div>
    SessionID: <%= SessionID %>
</div>
...

每次按下 F5 键,输出结果都会改变,与浏览器无关。

14个回答

248

这就是原因。

使用基于cookie的会话状态时,ASP.NET在使用Session对象之前不会为会话数据分配存储空间。因此,在访问Session对象之前,每个页面请求都会生成一个新的会话ID。如果您的应用程序需要一个静态会话ID来维持整个会话,可以实现应用程序的Global.asax文件中的Session_Start方法并将数据存储在Session对象中以修复会话ID,或者您可以在应用程序的其他部分中使用代码显式地将数据存储在Session对象中。

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.sessionid.aspx

因此,除非您在后端访问会话对象,否则每个请求都会生成一个新的sessionId。

编辑

这段代码必须添加到Global.asax文件中。它向Session对象添加一个条目,以便您可以固定会话直到过期。

protected void Session_Start(Object sender, EventArgs e) 
{
    Session["init"] = 0;
}

23
我不知道这件事,之前也没有遇到过问题,但知道这个信息很有趣。 - Pharabus
3
有趣的是,这解决了我的问题——但是在使用代码库约6个月之后才出现了问题。我无法想出为什么会突然发生改变,有人能提出sessionid突然被重置的原因吗? - user32826
2
@KumarHarsh:一旦您将任何对象存储在会话中,会话ID将保持不变。这就是我所说的“除非您在后端访问会话对象...”的意思。一旦您分配了someid,会话ID将保持不变。请注意,此答案已经超过4年了,不确定是否有关于此方面的任何修改。 - Claudio Redi
9
我注意到只需在 Global.asax 中添加一个空的 Session_Start 方法即可使其工作。感谢 @Claudio 的提示。 - Pedro
1
@Moo:这个对我来说一直很好用,大约使用了6年,直到我决定清理我的global.asax并删除那些方法体为空的方法,其中包括一个空的Session_Start方法。我重新添加了该方法,现在一切都正常工作了。 - Pedro
显示剩余9条评论

100

即使Session对象已经像Cladudio所演示的那样初始化,还有一个更隐蔽的原因可能导致这种情况发生。

在Web.config中,如果存在一个<httpCookies>条目,该条目设置为requireSSL="true",但实际上您并未使用HTTPS来进行特定请求,则会导致会话cookie不被发送(或者也许没有返回,我不确定是哪一种情况),这意味着每个请求都会得到一个全新的会话。

我通过艰苦的摸索才发现了这个问题,花费了数小时在我的源代码控制中来回切换多次提交,最终找到哪个具体的更改破坏了我的应用程序。


5
我知道这个,但每隔三个月左右我还是会忘记,然后花几个小时来调试。 - yakya
在我的情况下,我正在本地主机上进行测试,并且web.config中的“requireSSL”设置为“true”。谢谢。 - William Pereira
这是我的情况,我花了太多时间来尝试解决它(因为有一个不同的web.config文件,导致我走了弯路)。 - jmoreno
1
你在上面提出的建议仍然有助于2018年。这是最常见的情况。谢谢! - Vijay Bansal

6
在我的情况下,我发现会话cookie的域名包含www.前缀,而我请求的页面没有www.
www.添加到URL中立即解决了问题。后来,我将cookie的域设置为.mysite.com,而不是www.mysite.com

5
我的问题是我们在web.config文件中设置了以下内容: <httpCookies httpOnlyCookies="true" requireSSL="true"/> 这意味着在非SSL(默认情况下)调试时,认证cookie将不会被发送回服务器。这意味着服务器会为每个请求向客户端发送一个新的认证cookie(带有新会话)。
解决方法是:在web.config中将requiressl设置为false,在web.release.config中设置为true,或在调试时打开SSL。详情请参见以下链接:turn on SSL

这与Neville Cook 2011年的回答有何不同? - Ian Kemp

4
使用Neville的答案(在web.config中删除requireSSL = true)并且稍微修改Joel Etherton的代码,以下是应该处理在SSL模式和非SSL模式下运行的站点的代码,具体取决于用户和页面(我正在返回到代码并尚未在SSL上测试它,但预计它应该工作-以后会太忙无法返回到这里,因此在这里):
if (HttpContext.Current.Response.Cookies.Count > 0)
        {
            foreach (string s in HttpContext.Current.Response.Cookies.AllKeys)
            {
                if (s == FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid")
                {
                    HttpContext.Current.Response.Cookies[s].Secure = HttpContext.Current.Request.IsSecureConnection;
                }
            }
        }

3
在我的情况下,这是因为我在从外部应用程序的网关重定向后修改了会话。因此,因为我在该页面URL中使用的是IP而不是localhost,它实际上被认为是具有不同会话的不同网站。
总之,如果您正在调试托管在IIS上的应用程序,并在各种页面中混合使用http://Iphttp://localhost,请更加注意。

2

我遇到的问题出现在一个Microsoft MediaRoom IPTV应用程序中。结果发现MPF MRML应用程序不支持cookie;通过在web.config中更改为使用无cookie会话来解决我的问题。

<sessionState cookieless="true"  />

这是一篇非常古老的关于 Cookieless ASP.NET 的文章: Cookieless ASP.NET

2
另一个导致SessionID在请求之间更改的可能性,即使定义了Session_OnStart和/或初始化了会话,是URL主机名包含无效字符(例如下划线)。我认为这是IE特有的(未经验证),但如果您的URL是http://server_name/app,那么IE将阻止所有cookie,并且您的会话信息将无法在请求之间访问。
事实上,每个请求都会在服务器上启动单独的会话,因此如果您的页面包含多个图像、脚本标记等,则每个GET请求都将在服务器上产生不同的会话。
更多信息:http://support.microsoft.com/kb/316112

2
在我的开发和测试环境中,这种情况经常发生。在尝试了上述所有解决方案而没有成功后,我发现通过删除所有会话cookie可以解决这个问题。 Web Developer扩展使此操作非常容易。通常我使用Firefox进行测试和开发,但在Chrome中测试时也出现过这种情况。此修复程序在Chrome中也有效。
目前我还没有在生产环境中遇到过这种情况,也没有收到任何人无法登录的报告。这似乎只发生在将会话cookie设置为安全后。在过去,当它们不是安全的时候,从未发生过这种情况。
更新:这种情况仅在我们更改会话cookie以使其安全后发生。我已确定确切的问题是浏览器中存在两个或以上具有相同路径和域的会话cookie。始终存在问题的是具有空值或null值的cookie。在删除该特定cookie后,问题得到解决。我还在Global.asax.cs Sessin_Start方法中添加了代码来检查此空cookie,并如果有,则将其过期日期设置为过去的某个时间。
HttpCookieCollection cookies = Response.Cookies;
for (int i = 0; i < cookies.Count; i++)
{
    HttpCookie cookie = cookies.Get(i);

    if (cookie != null)
    {
        if ((cookie.Name == "ASP.NET_SessionId" || cookie.Name == "ASP.NET_SessionID") && String.IsNullOrEmpty(cookie.Value))
        {
            //Try resetting the expiration date of the session cookie to something in the past and/or deleting it.
            //Reset the expiration time of the cookie to one hour, one minute and one second in the past
            if (Response.Cookies[cookie.Name] != null)
                Response.Cookies[cookie.Name].Expires = DateTime.Today.Subtract(new TimeSpan(1, 1, 1));
        }
    }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接