在IIS7中将表单发布到404 + HttpHandler:为什么所有POST数据都丢失了?
好的,这听起来可能有点混乱和复杂,请耐心等待。
我们编写了一个框架,使我们可以定义友好的URL。如果浏览到任意URL,IIS会尝试显示404错误(在某些情况下为403; 14或者405)。但是,设置了IIS,以便将针对那些特定错误的所有内容发送到.aspx文件。这使我们可以实现HttpHandler来处理请求和执行操作,这涉及找到相关的模板,然后执行与之关联的所有内容。
现在,这一切都可以在IIS 5和IIS 6中使用,并且在某种程度上也可以在IIS7上使用,但是要注意的一点是,在发布表单时会发生这种情况。
请参见,将表单发布到不存在的URL时,IIS会说"啊,但该URL不存在",并抛出405"不允许的方法"错误。由于我们要告诉IIS将这些错误重定向到.aspx页,并因此使用HttpHandler进行处理,因此这通常不是问题。但是从IIS7开始,所有POST信息在重定向到405后都丢失了。因此,我们不能再做涉及表单的最琐碎的事情。
为了解决这个问题,我们尝试使用HttpModule,它保留POST数据,但似乎在正确的时间(需要时)没有初始化的Session。我们还尝试对所有请求使用HttpModule,不仅是命中404/403; 14/405的丢失请求,而且这意味着图像,css,js等内容正在由.NET代码处理,这效率极低。
这使我想到了一个实际的问题:是否有人遇到过这个问题,是否有人提出任何建议或者知道该怎么做才能使事情再次起作用?到目前为止,有人建议使用Microsoft自己的URL重写模块。这将有助于解决我们的问题吗?
谢谢。
解决方案
只是一个猜测:在处理请求的IIS7的%windir%\ system32 \ inetsrv \ config \ applicationhost.config中指定的处理程序根本不允许POST动词通过,它正在评估该规则,然后确定是否URL不存在。
由于IIS7从上到下使用.net,因此使用HttpModule不会产生任何性能开销,因此实际上有多个托管HttpModule始终用于每个请求。引发BeginRequest事件时,可能尚未将SessionStateModule添加到Modules集合中,因此,如果我们尝试在此事件期间处理请求,则将没有会话状态信息。设置HttpContext.Handler属性将在请求的处理程序需要它时初始化会话状态,因此我们只需将处理程序设置为实现IRequiresSessionState的404页面即可。尽管我们可能需要为IsMissing()方法编写一个不同的实现,但是下面的代码应该可以解决问题:
using System.Web; using System.Web.UI; class Smart404Module : IHttpModule { public void Dispose() {} public void Init(HttpApplication context) { context.BeginRequest += new System.EventHandler(DoMapping); } void DoMapping(object sender, System.EventArgs e) { HttpApplication app = (HttpApplication)sender; if (IsMissing(app.Context)) app.Context.Handler = PageParser.GetCompiledPageInstance( "~/404.aspx", app.Request.MapPath("~/404.aspx"), app.Context); } bool IsMissing(HttpContext context) { string path = context.Request.MapPath(context.Request.Url.AbsolutePath); if (System.IO.File.Exists(path) || (System.IO.Directory.Exists(path) && System.IO.File.Exists(System.IO.Path.Combine(path, "default.aspx")))) return true; return false; } }
编辑:我添加了IsMissing()的实现
注意:在IIS7上,默认情况下,会话状态模块不会全局运行。有两个选项:对所有请求启用会话状态模块(请参阅上面有关对所有请求类型运行托管模块的评论),或者可以使用反射来访问System.Web.dll中的内部成员。
是的,我绝对建议我们重写URL(使用Microsoft的IIS7或者许多替代方法之一)。这是专为提供友好的URL而设计的,而错误文档是失败的最后支持,这往往会破坏传入的数据,因此可能不是我们所期望的。
Microsoft为此发布了一个修补程序:
http://support.microsoft.com/default.aspx/kb/956578
IIS 7中的发布变量未传递给自定义错误处理程序的问题已在Vista的Service Pack 2中得到修复。还没有在Windows Server上尝试过它,但是我敢肯定它也将在此修复。