我的示例设置是:IIS8 Express服务器上的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集合的此行为?
解决方法
背景
这是对它的描述:
在IIS7中,每次离开asp.net管道返回IIS管道时,如果需要,都会添加cookie头.在集成模式下,您可以在大多数事件之间保留asp.net管道.
因此,当它根据需要写出cookie时,它会检查是否已删除任何cookie.如果没有,它会检查是否添加了任何cookie.如果是这样,它会为该cookie添加标题.它还会检查是否有任何cookie被修改.如果是这样,它会为它添加标题.虽然它迭代了cookie,但它会记录任何被修改的内容.
如果删除了任何cookie,或者任何cookie被修改,那么它将删除所有Set-Cookie标头,并写出一个新的集合. (或者至少它会尝试.如果标题已被刷新,那么显然这是不可能的.)
到现在为止还挺好.但是,在重新编译托管管道时,我们会读回任何响应头并重新构建响应cookie.这是必需的,因为一些非托管模块可能添加了新的响应cookie.但是虽然添加了cookie会导致它们被标记为已添加,但代码会立即取消添加标记.所以到目前为止一切都还不错,对吗?
好吧不完全是.每次向Response.Cookies集合添加cookie(或从中删除)时,Request.Cookies集合都完全被重新加载,然后将响应cookie添加到其中,再次在HttpCookie对象上设置add标志.这是错误.这会导致每次添加或删除任何其他cookie时,都会在每个响应cookie上设置Added标记.
这意味着每次租用托管管道时,除了最后一个cookie之外的所有cookie都会被复制,但不会对cookie进行任何更改.如果您添加一个cookie,那么之前添加的所有cookie都将被复制.但是,如果您更改任何cookie,或从Response.Cookies集合中删除任何cookie,那么您将消除以前发生的所有重复项.
Hackish Workaround
要解决此错误,只需添加和删除一些任意cookie,或在标题写出的同一事件中修改cookie.通常这将是EndRequest,除非你在应用程序的任何地方使用Server.Transfer,Server.Redirect,Response.Flush或Reponse.End(除非你将endReponse参数设置为false),在这种情况下你必须在发生这种情况的同一事件.另外,请不要忘记库中出现的任何问题或您使用的任何HttpModule.基本上,您只想将以下代码添加到每个事件:
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. }