11

在将响应流写入线路期间,ASP.NET cookie 处理似乎存在烦人的错误。Set-Cookie标题是随机相乘的。

我的示例设置是:IIS8 快速服务器上的ASP.NET MVC4,但同样的问题发生在IIS7 集成模式上,我在 2009 年发现了关于IIS6相同问题的帖子。这似乎是存在一段时间的问题。

例如,在 Global.asax.cs 中,我订阅 BeginRequest 事件并在我的事件处理程序中写入 HttpResponse.Cookie 集合:

public class MvcApplication : System.Web.HttpApplication
{
    public override void Init()
    {
        base.Init();
        BeginRequest += OnBeginRequest;
    }

    void OnBeginRequest(object sender, EventArgs e)
    {
        Response.Cookies.Set(new HttpCookie("OnBeginRequest", "0"));
    }
}

这将已经输出两次“OnBeginRequest”Set-Cookie 标头。但是,如果对所有 HttpApplication 事件(AuthenticateRequest、AcquireRequestState 等......总共约 20 个事件)进行类似操作,则发送到浏览器的 http 响应标头将写入大量重复项。从乞讨开始写入 cookie 的事件也很明显。

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnMapRequestHandler=7; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnMapRequestHandler=7; path=/
Set-Cookie: OnPostMapRequestHandler=8; path=/
Set-Cookie: OnAcquireRequestState=9; path=/
Set-Cookie: OnPostAcquireRequestState=10; path=/
Set-Cookie: OnPreRequestHandlerExecute=11; path=/
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnMapRequestHandler=7; path=/
Set-Cookie: OnPostMapRequestHandler=8; path=/
Set-Cookie: OnAcquireRequestState=9; path=/
Set-Cookie: OnPostAcquireRequestState=10; path=/
Set-Cookie: OnPreRequestHandlerExecute=11; path=/
Set-Cookie: OnPostRequestHandlerExecute=12; path=/
Set-Cookie: OnReleaseRequestState=13; path=/
Set-Cookie: OnPostReleaseRequestState=14; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnMapRequestHandler=7; path=/
Set-Cookie: OnPostMapRequestHandler=8; path=/
Set-Cookie: OnAcquireRequestState=9; path=/
Set-Cookie: OnPostAcquireRequestState=10; path=/
Set-Cookie: OnPreRequestHandlerExecute=11; path=/
Set-Cookie: OnPostRequestHandlerExecute=12; path=/
Set-Cookie: OnReleaseRequestState=13; path=/
Set-Cookie: OnPostReleaseRequestState=14; path=/
Set-Cookie: OnUpdateRequestCache=15; path=/
Set-Cookie: OnPostUpdateRequestCache=16; path=/
Set-Cookie: OnLogRequest=17; path=/
Set-Cookie: OnPostLogRequest=18; path=/
Set-Cookie: OnEndRequest=19; path=/
Set-Cookie: OnBeginRequest=0; path=/
Set-Cookie: OnAuthenticateRequest=1; path=/
Set-Cookie: OnPostAuthenticateRequest=2; path=/
Set-Cookie: OnAuthorizeRequest=3; path=/
Set-Cookie: OnPostAuthorizeRequest=4; path=/
Set-Cookie: OnResolveRequestCache=5; path=/
Set-Cookie: OnPostResolveRequestCache=6; path=/
Set-Cookie: OnMapRequestHandler=7; path=/
Set-Cookie: OnPostMapRequestHandler=8; path=/
Set-Cookie: OnAcquireRequestState=9; path=/
Set-Cookie: OnPostAcquireRequestState=10; path=/
Set-Cookie: OnPreRequestHandlerExecute=11; path=/
Set-Cookie: OnPostRequestHandlerExecute=12; path=/
Set-Cookie: OnReleaseRequestState=13; path=/
Set-Cookie: OnPostReleaseRequestState=14; path=/
Set-Cookie: OnUpdateRequestCache=15; path=/
Set-Cookie: OnPostUpdateRequestCache=16; path=/
Set-Cookie: OnLogRequest=17; path=/
Set-Cookie: OnPostLogRequest=18; path=/
Set-Cookie: OnEndRequest=19; path=/
Set-Cookie: OnPreSendRequestContent=20; path=/
Set-Cookie: OnPreSendRequestHeaders=21; path=/
X-Powered-By: ASP.NET
Date: Mon, 20 May 2013 10:47:20 GMT
Content-Length: 4002

更糟糕的是,如果在 1 个事件处理程序中写入相同的 cookie,然后在另一个事件处理程序中更新,则标题中将出现具有不同值的重复项。

是否有任何设置或解决方法可以防止这种默认HttpResponse.Cookies收集行为?

4

4 回答 4

6

影响 IIS 7 的错误可能与受影响的 IIS6 不同。此错误已在 4.7 中修复,有问题的错误具有以下 ID DevID 289778:.

背景

下面是它的描述: 在 IIS7 中,每次离开 asp.net 管道返回到 IIS 管道时,如果需要,都会添加 cookie 标头。在集成模式下,您将 asp.net 管道保留在大多数事件之间。

因此,当它根据需要写出 cookie 时,它​​会检查是否已删除任何 cookie。如果没有,它会检查是否添加了任何 cookie。如果是这样,它会为该 cookie 添加一个标头。它还会检查是否有任何 cookie 已被修改。如果是这样,它会为它添加一个标题。当它迭代 cookie 时,它​​会记下任何被修改的内容。

如果删除了任何 cookie,或者修改了任何 cookie,则它会删除所有 Set-Cookie 标头,并写出一个新集。(或者至少它会尝试。如果标题已被刷新,那么显然这是不可能的。)

到目前为止,一切都很好。但是,在重新进入托管管道时,我们会读回任何响应标头并重新构建响应 cookie。这是必需的,因为某些非托管模块可能添加了新的响应 cookie。这样做时,它不会为从响应标头复制的任何 cookie 设置添加的标志。到目前为止,一切都还不错,对吧?

错误

不完全是。每次将 cookie 添加到集合(或从集合中删除)时Response.CookiesRequest.Cookies集合都会完全重新加载,然后将响应 cookie 添加到其中,HttpCookie再次在对象上设置添加标志。这是错误。这会导致每次添加或删除任何其他 cookie 时都会在每个响应 cookie 上设置已添加标志。

这意味着如果您不修改或删除任何 cookie,但您添加了至少一个,那么之前在其他管道阶段添加的所有 cookie 都将被复制。但是,如果您更改任何 cookie,或从Response.Cookies集合中删除任何 cookie,那么您将消除以前发生的所有重复项。

黑客的解决方法

要解决此错误,只需添加和删除一些任意 cookie,或在写出标头的同一事件期间修改 cookie。通常这将是EndRequest,除非您在应用程序的任何位置使用Server.TransferServer.RedirectResponse.FlushReponse.End(除非您将endReponse参数设置为 false),在这种情况下,您必须在发生这些情况的同时执行此操作。也不要忘记库中出现的任何情况,或您使用的任何 HttpModules。基本上,您只想将以下代码添加到每个事件中:

try{
   var guid=Guid.NewGuid();
   context.Response.Cookies.Add(new HttpCookie(guid.ToString(),string.Empty);
   context.Response.Cookies.Remove(guid.ToString());
}
catch(HttpException)
{
   //This means the headers were already written,
   //in which case we need not do anything.
}
于 2015-02-10T20:21:05.350 回答
1

其他重复 cookie 错误描述:
上下文:Web 表单应用程序(使用表单身份验证和 url 重写)
问题:会话 cookie 系统地发送了两次(除了应用程序编译后收到的第一个请求)。
平台:IIS 10/.NET Framework 4.7.2

凯文解决方案确实可以解决该错误(也)。

注意:
不需要随机的 cookie 名称。
在 asp.net Web 表单页面上,此解决方法可用于 Load 事件。

于 2019-07-08T10:44:06.640 回答
-1

如果您在更改 cookie 值后在页面之间导航而不返回客户端 (server.Transfer),则 cookie 将被复制。

于 2014-02-12T13:48:38.833 回答
-1

当您将任何值设置为 cookie 时,请先将其清除,使用.Clear()

var cookie = this.Request.Cookies.Get("MyCookie");
if (cookie == null)
{
   cookie = new HttpCookie("MyCookie");
   this.Response.Cookies.Add(cookie);
}
else
{
   cookie.Values.Clear();                       //crear firstly..
   cookie.Values.Add("AnyKey", "AnyValue");
}
于 2013-07-26T05:20:30.100 回答