【问题标题】:customErrors vs Custom modulescustomErrors 与自定义模块
【发布时间】:2016-10-20 10:13:40
【问题描述】:

我目前有 httpErrors 设置来处理这里的 500 个:-

<httpErrors errorMode="Custom" existingResponse="Replace">
        ......
        <remove statusCode="500"/>
        <error statusCode="500" path="/server-error" responseMode="ExecuteURL"/>
</httpErrors>

这工作正常,但在 iis 收到错误的情况下,我仍然会得到黄屏死机。一个例子是实体框架无法连接到数据库并且我收到:-

无法打开登录请求的数据库“Test-DB”。
登录失败。
用户“sa”登录失败。

我已经设置了customErrors 来处理这个问题:-

<customErrors mode="On" defaultRedirect="error.html" redirectMode="ResponseRedirect">
        <error statusCode="500" redirect="error.html" />
</customErrors>

只要没有modules 而没有preCondition="managedHandler",它就会按预期工作。

我有几个处理图像和 css 文件的模块,它们在同一个项目中。

<modules runAllManagedModulesForAllRequests="false">
        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
        <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
        <add name="ImageHandler" type="foo.bar.ProductImageHandlerHttpModule" />
        <add name="CustomCssHandler" type="foo.bar.CustomCssHttpModule" />
        <add name="Glimpse" type="Glimpse.AspNet.HttpModule, Glimpse.AspNet" preCondition="integratedMode" />
</modules>

评论这些,我得到error.html,把它们留在里面,我得到

运行时错误
说明:处理您的程序时发生异常 要求。此外,在执行 第一个异常的自定义错误页面。请求已 终止。

显示项目中的模块在尝试显示 error.html 时也出错。

有人知道修复/解决方法吗?

【问题讨论】:

  • 嗨@BenG,我试图重现这个问题。我认为问题在于 preCondition="managedHandler" 尽管msdn.microsoft.com/en-us/library/ms690693(v=vs.90).aspx 的文档说它不应该运行具有 preCondition="managedHandler" 对于非托管这样的 html 的模块,但它仍然可以。我只是想找出为什么 IIS 仍然为具有前提条件的 html 文件运行模块。
  • @MurtazaTahirAli 模块 with 前提条件不适合我。它的另一个 foo.bar. 自定义的会引发下一个错误。

标签: c# asp.net asp.net-mvc iis httpmodule


【解决方案1】:

这是一个艰难的情况 - 您的错误来自 HttpModule,它针对每个请求运行 - 包括对 error.html 页面的请求。一种方法是仅通过您的服务器路由静态文件(例如 error.html) - 并在 .NET 级别忽略它们;这可能并不总是可能的(有时在 .NET 级别处理静态文件很方便)。我能想到的唯一其他方法是将 global.asax 挂钩到错误事件并自己处理(这将忽略 customErrors

类似:

public class Global : System.Web.HttpApplication
{
    protected void Application_Error(object sender, EventArgs e)
    {
        // is there an error ?
        var error = Server.GetLastError();
        if (error != null)
        {
            // mark the error as - "i'll handle it myself"
            Server.ClearError();
            // load error.html manually & dump it to response
            var content = File.ReadAllText(Server.MapPath("~/error.html"));
            Context.Response.Write(content);
            // set correct error code
            Context.Response.StatusCode = 500;
        }
    }
}

注意:这可以解决,但你看到了一般原则......

【讨论】:

  • 这并没有 100% 解决问题,因为如果您在站点启动时遇到错误,则 response 不可用,但Application_Error 似乎是最一致的答案,而且这个首先,我会将赏金奖励给你。谢谢。
【解决方案2】:

正如@Ondrej 所说,处理自定义错误页面时发生的另一个错误来自HttpModule 上的未处理异常,因此有必要跳过或绕过web.config 文件上的customErrors 部分。

除了生成自定义 HTML 错误页面之外,此代码还包括如何跳过从 IIS 生成的自定义错误:

protected void Application_Error(Object sender, EventArgs e)
{
    // Get last error occurred
    var exception = Server.GetLastError();

    // catch unhandled exceptions
    if (exception is HttpUnhandledException)
    {
        // handle the error by ASP .NET itself
        Server.ClearError();
        
        // write status code handling
        HttpContext.Current.Response.WriteFile(Server.MapPath("~/error.html"));
        HttpContext.Current.Response.StatusCode = 500;
        HttpContext.Current.Response.StatusDescription = "Internal Server Error";

        // set ASP .NET handlers instead of using IIS handlers
        HttpContext.Current.Response.TrySkipIisCustomErrors = true;
    }
}

此外,要摆脱 IIS 生成的 YSOD 页面,您可以设置 existingResponse 属性以将错误处理传递给 ASP .NET Application_Error 方法,如下所示:

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="PassThrough">
    <remove statusCode="500" />
    <error statusCode="500" responseMode="File" path="/error.html" />
    </httpErrors>
</system.webServer>

这些设置背后的原因来自 Kanwaljeet Singla 的解释 (source here):

现有响应

此部分级别属性的值告诉自定义错误模块要做什么 当响应文本不为空时执行。如果一个模块调用 IHttpResponse::SetStatus 设置错误代码并设置 响应文本,existingResponse 属性告诉是否自定义错误模块 应该用自己的错误文本替换当前响应文本,或者应该 它让当前的响应文本通过。 Asp.Net 和 WCF 是 设置错误响应文本的模块示例。这个属性可以 设置为以下三个值。

  • Replace - 此值使自定义错误模块始终将错误信息替换为自定义错误模块生成的文本。如果 existingResponse 设置为“替换”,错误/异常由 Asp.Net/WCF 被 IIS7 错误替换。

  • PassThrough – 如果existingResponse 被视为“PassThrough”,自定义错误模块将始终传递来自模块的响应。 此设置将使自定义错误模块返回空白响应,如果 模块不设置任何文本。

  • Auto - 这是默认值,并告诉自定义错误模块做 正确 的事情。客户看到的实际错误文本将是 影响取决于返回的 fTrySkipCustomErrors 的值 IHttpResponse::GetStatus 调用。当 TrySkipCustomErrors 设置为 是的,自定义错误模块会让响应通过,但如果它 设置为 false,自定义错误模块用自己的文本替换文本。 Asp.Net/WCF 使用 TrySkipCustomErrors 调用 IHttpResponse::SetStatus true 以便 IIS 不会用自己的错误覆盖它们的错误。什么时候 有效的 errorMode 是“详细”并且响应是非空的,这 existingResponse 的值将充当“PassThrough”,无论 TrySkipCustomErrors 的值。

希望这可以在为未处理的异常响应设置自定义错误页面时找出基本的东西。

MSDN 参考资料:

https://msdn.microsoft.com/en-us/library/ms690576(v=vs.90).aspx

https://msdn.microsoft.com/en-us/library/system.web.httpresponse.tryskipiiscustomerrors(v=vs.110).aspx

SO 参考资料:

IIS7 Overrides customErrors when setting Response.StatusCode?

How to send status code "500" for generic error page in IIS?

Getting IIS7 'one liner' error when using custom error settings in web.config

【讨论】:

  • 刚试过这个,不幸的是我得到了错误Response is not available in this context.Response.WriteFile(Server.MapPath("~/error.html"));
  • 我意识到Application_Error方法上的Response属性来自HttpApplication类而不是HttpContext.Current.Response,当前上下文可能需要激活Response.WriteFile
【解决方案3】:

似乎如果您的 iis 设置为集成模式,那么模块仍将针对静态文件运行。如果您将其设置为经典模式,它将忽略静态文件的托管模块。

请参阅此线程以获取更多信息,请参阅 João Angelo Requests for static files are hitting the managed code in ASP.NET MVC3 的答案

解决方法是您将处理程序更改为不引发异常,或者将 iis 更改为经典模式,因此如果任何处理程序或其他部分引发异常并且 iis 重定向到 error.html,则任何管理模块都不应命中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2020-06-24
    • 2015-09-03
    • 2012-01-02
    • 2012-05-29
    相关资源
    最近更新 更多