为什么我在执行Server.Transfer从Application_Error和errorMode =“Custom”时看到2个错误页面?

时间:2010-10-18 14:06:32

标签: asp.net iis-7 error-handling

我的问题与此question密切相关。

以下是一个快速概要:我的应用程序在经典模式下运行。 我在Global.asax中有以下代码

    protected void Application_Error(Object sender, EventArgs e)
    {
        // ... boring stuff...
        HttpContext.Current.Server.Transfer("~/MyErrorPage.aspx", true);
    }

如果

发生错误,一切正常(即我看到MyErrorPage.aspx)
<httpErrors errorMode="Detailed" />

但是当errorMode="Custom"(或errorMode="DetailedLocalOnly"并且请求来自远程计算机时),我看到IIS自定义错误页面后跟我的错误页面(MyErrorPage.aspx)。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <!-- The contents of the default 500 page as configured in IIS 
         Which for me is the default %SystemDrive%\inetpub\custerr\<LANGUAGE-TAG>\500.htm
    -->
</html> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml" > 
    <!-- The contents of MyErrorPage.aspx -->
</html>

如果我从IIS错误页面部分删除默认的500错误页面,那么我得到以下输出(请注意,我得到“页面无法显示...”而不是自定义500页)

The page cannot be displayed because an internal server error has occurred.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml" > 
    <!-- The contents of MyErrorPage.aspx -->
</html>

如果我使用调试器逐步执行代码,那么当我跳过Server.Transfer语句时,我看到IIS 500页面被刷新到客户端。
然后,我的错误页面会在MyErrorPage.aspx的正常页面生命周期后发送到浏览器(如您所料)。 我已经尝试(在绝望中)在Server.Transfer之前清除响应的内容(HttpContext.Current.Response.Clear())但是没有效果。 我也尝试在转移之前调用Server.ClearError(),但这也没有效果。

现在根据链接的问题,“修复”是设置errormode="Detailed"但我不想看到ASP.Net中未处理的错误的详细错误页面 - 例如我更喜欢如果我输入网址myApp/DoesNotExist.html,请参阅IIS自定义404页面而不是详细页面。 [我们的一些客户绝对坚持认为用户永远不会看到详细的错误页面,因为它被视为潜在的安全漏洞。]

另一个“修复”是重定向而不是进行服务器传输但是我希望在可能的情况下进行传输:执行传输意味着浏览器的URL不变,这意味着,例如,如果错误发生是因为应用程序刚刚启动时,他们可以按F5重试请求。重定向显然会将浏览器的地址更改为错误页面。

有没有人解释为什么我会看到这种行为?有没有人有解决方案?

提前致谢。

修改

我已经敲了一个演示行为的小应用程序:

http://rapidshare.com/files/427244682/Err.zip

[确保应用程序在经典模式下运行。]

如果单击同时设置了transfer和setstatus args的链接,则会看到问题所在。 BANG

3 个答案:

答案 0 :(得分:0)

将以下属性添加到<httpErrors>标记中:

existingResponse="PassThrough"

那应该解决它。 PassThrough时默认为errorMode="Detailed"

http://blogs.iis.net/ksingla/archive/2008/02/18/what-to-expect-from-iis7-custom-error-module.aspx

的更多信息

答案 1 :(得分:0)

Response Response.TrySkipIisCustomErrors上有一个属性 - 显然应该阻止IIS注入它自己的错误页面代码。大概你可以将其设置为true,因为错误会以某种方式发生,因此您不会获得实际错误的自定义错误页面,但404仍保留在IIS中。

答案 2 :(得分:0)

如果您的自定义错误页面逻辑仅基于错误编号,则应在web.config中定义自定义错误页面。并根据Server.GetLastError()中的状态代码在通用错误页面中设置状态代码。 如果您指定defaultResponseMode =“ExecuteURL”,那么您将拥有客户端浏览器中的requsted页面的URL。

<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/ErrorPages/CustomErrorPage.aspx" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/ErrorPages/404.aspx"/>
      <error statusCode="500" redirect ="~/ErrorPages/500.aspx"/>
</customErrors>
</system.web>

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace" defaultPath="~/ErrorPages/CustomErrorPage.aspx" defaultResponseMode="ExecuteURL">
      <error statusCode="404" path="~/ErrorPages/404.aspx"/>
      <error statusCode="500" path ="~/ErrorPages/500.aspx"/>
    </httpErrors>
</system.webServer>

并将其放在CustomErrorPage的Page_Load

    Exception ex = Server.GetLastError();
    if (ex is HttpException){
        Response.StatusCode = ((HttpException)ex).GetHttpCode();
    }

通过这种方式,您无需使用Server.Transfer(它由enviromnet隐式完成),并且您有一个通用页面来处理未明确处理的错误。