【问题标题】:Custom Error Handling in web.config / Global.asax not handling non-existant directoryweb.config / Global.asax 中的自定义错误处理不处理不存在的目录
【发布时间】:2011-04-14 14:22:34
【问题描述】:

问题是:为什么自定义错误处理不适用于不存在的路径/目录?

使用固定代码更新(感谢大家的输入):

* 更新了 web.config 和 global.asax 的代码*

<httpErrors errorMode="Custom">
        <remove statusCode="500" subStatusCode="-1" />
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL" />
        <error statusCode="500" subStatusCode="-1"  prefixLanguageFilePath="" path="/*****.aspx"  responseMode="ExecuteURL"/>
    </httpErrors>

    added this to the global.asax to stop IIS from handling my 500 errors
    after @Kev's suggestions IIS handled my 500's these lines fixed that
    HttpApplication myApplication = new HttpApplication();
    myApplication.Response.TrySkipIisCustomErrors = true;

我们在web.configglobal.asax 中有一个带有自定义错误处理的站点设置(设置如下所示)。我们能够毫无问题地处理所有 404 和 500。错误在global.asax 中的Application_Error 中捕获,记录到数据库然后使用HttpContext 我们设置状态代码并使用Server.Transfer() 将用户移动到适当的错误页面(重定向导致302,和伤害 SEO)。

问题是当用户输入http://www.example.com/whatever 时,Firefox 会显示一个空白页面,而 IE 会显示 IE 404 页面。 Firebug 显示没有触发任何状态代码,当我调试解决方案时,global.asax 中没有遇到我设置的断点。奇怪的是用户可以输入http://www.example.com/whatever/hmm.aspx 并且会出现错误。似乎它只适用于不存在的页面,而不是不存在的路径/目录。

下面是我的web.config 错误代码和我的global.asax 应用程序错误代码。

我添加了 ** 来隐藏信息,它们中有有效的.aspx 页面:

网络配置:

<customErrors defaultRedirect="~/******.aspx" mode="On" 
              redirectMode="ResponseRewrite">
    <error statusCode="500" redirect="~/*****.aspx" />
    <error statusCode="404" redirect="~/*****.aspx" />
</customErrors>

    <httpErrors errorMode="Custom">
        <remove statusCode="500" subStatusCode="-1" />
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL" />
        <error statusCode="500" subStatusCode="-1"  prefixLanguageFilePath="" path="/*****.aspx"  responseMode="ExecuteURL"/>
    </httpErrors>

代码:

protected void Application_Error(Object sender, EventArgs e)
{
    // At this point we have information about the error
    HttpContext ctx = HttpContext.Current;

    // set the exception to the Context 
    Exception exception = ctx.Server.GetLastError();

    // get the status code of the Error
    int httpCode = ((HttpException)exception).GetHttpCode();

    // get the IP Address
    String strHostName = string.Empty;
    String ipAddress_s = string.Empty;
    strHostName = System.Net.Dns.GetHostName();

    System.Net.IPHostEntry ipEntry = System.Net.Dns.GetHostByName(strHostName);
    System.Net.IPAddress[] addr = ipEntry.AddressList;

    for (int i = 0; i < addr.Length; i++)
    {
        ipAddress_s += "IP Address {" + (i + 1) + "} " + 
                            addr[i].ToString() + Environment.NewLine;
    }

    // setup the error info one for user display and one for the DB Insert
    string errorInfo =
       "<br /><b>Error Location:</b> " + ctx.Request.Url.ToString() +
       "<br /><br /><b>Error Source:</b> " + exception.Source +
       "<br /><br /><b>Error Try/Catch:</b> " + exception.InnerException +
       "<br /><br /><b>Error Info:</b> " + exception.Message +
       "<br /><br /><b>Status Code:</b> " + httpCode +
       "<br /><br /><b>Stack trace:</b> " + exception.StackTrace;
    string errorInfoDB =
       "||Error Location: " + ctx.Request.Url.ToString() +
       "||Error Source: " + exception.Source +
       "||Error Try/Catch: " + exception.InnerException +
       "||Error Info: " + exception.Message +
       "||HttpErrorCode: " + httpCode +
       "||Stack trace: " + exception.StackTrace +
       "||IP Address: " + ipAddress_s;

    // clean the input befor you put it in the DB
    char quote = (char)34;
    char filler = (char)124;
    char tick = (char)39;
    char greaterThan = (char)60;
    char lessThan = (char)62;
    errorInfo = errorInfo.Replace(quote, filler);
    errorInfo = errorInfo.Replace(tick, filler);
    errorInfo = errorInfo.Replace(greaterThan, filler);
    errorInfo = errorInfo.Replace(lessThan, filler);

    errorInfoDB = errorInfoDB.Replace(quote, filler);
    errorInfoDB = errorInfoDB.Replace(tick, filler);
    errorInfoDB = errorInfoDB.Replace(greaterThan, filler);
    errorInfoDB = errorInfoDB.Replace(lessThan, filler);

    string pattern = string.Empty;
    string replacement = "sQueEl";
    pattern = "/cookie|SELECT|UPDATE|INSERT|INTO|DELETE|FROM|NOT IN|WHERE|TABLE|DROP|script*/ig";
    errorInfoDB = Regex.Replace(errorInfoDB, pattern, replacement);

    pattern = "/cookie|select|update|insert|into|delete|from|not in|where|table|drop|script*/ig";
    errorInfoDB = Regex.Replace(errorInfoDB, pattern, replacement);


    if (httpCode == 404)
    {
        InSert_To_DB_Class(*****, *****, *****, *****, *****, errorInfoDB);
    }
    else
    {
        InSert_To_DB_Class(*****, *****, *****, *****, *****, errorInfoDB);
    }

    // set the error info to the session variable to display to the allowed users
    Application["AppError"] = errorInfo;

    // clear the error now that is has been stored to a session
    ctx.Server.ClearError();
    ctx.Response.ClearHeaders();
    // set the status code so we can return it for SEO
    ctx.Response.StatusCode = httpCode;
    ctx.Response.TrySkipIisCustomErrors = true;
    HttpApplication myApplication = new HttpApplication();
    myApplication.Response.TrySkipIisCustomErrors = true;
    try
    {
        if (ctx.Request.RawUrl.Contains("/*****"))
        {
            // redirect to the error page
            ctx.Server.Transfer("~/*****.aspx", false);
        }
        else if(ctx.Request.RawUrl.Contains("/*****"))
        {
            ctx.Server.Transfer("~/*****/*****.aspx", false);
        }
        else
        {
            // check the httpCode
            if (httpCode == 404)
            {
                // set the page name they were trying to find to a session variable
                // this will be cleared in the ****** page
                Application["404_page"] = exception.Message; 
                // redirect to the 404 page
                ctx.Server.Transfer("~/*****", false);
            }
            else
            {
                // redirect to the error page
                ctx.Server.Transfer("~/*****", false);
            }
        }
    }
}

【问题讨论】:

  • 您的配置示例无效 - 请发布 实际 sn-ps 减去敏感数据。

标签: c# .net asp.net iis web-config


【解决方案1】:

从这条评论到失望先生:

谢谢,我在现场使用 IIS 7 本地和 IIS 7.5。找到材料后告诉我。

如果您的应用程序在配置为以经典管道模式运行的应用程序池中运行,则不适合 ASP.NET 的内容将不会到达 ASP.NET 运行时。即不存在的文件夹。这些将由 IIS 直接处理。

你有几个选择:

  1. 将应用程序池设置为集成管道模式。如果 IIS 的错误处理“吃掉”来自 ASP.NET 的 ASP.NET 404 和 500 状态代码,您可能还需要配置以下设置:

    <configuration>
      <system.webServer>
        <httpErrors existingResponse="PassThrough" />
      </system.webServer>
    </configuration>
    
  2. 如果应用程序在“集成管道”模式下表现不佳,但您只关心显示 404 响应的页面,请配置以下内容:

    <system.webServer>
      <httpErrors>
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" prefixLanguageFilePath="" 
               path="/404.aspx" responseMode="ExecuteURL" />
      </httpErrors>
    </system.webServer>
    

    您需要在页面中设置404 状态码,否则它只会返回一个200

    如果使用静态页面,例如:

    <error statusCode="404" prefixLanguageFilePath="" 
           path="404.html" responseMode="File" />
    

    这将返回一个404

  3. 如果应用程序在“集成管道”模式下表现不佳,并且您绝对必须通过错误处理程序传递 404 错误,那么您可能必须手动将通配符内容映射到 ASP.NET HttpHandler 以便此类请求执行击中管道。这将是一个次优的解决方案。

【讨论】:

  • 谢谢凯夫。我已经完成了您的一些建议,现在获取 IIS 404.0 页面以获取不存在的路径/目录。我删除了 ,它现在显示 IIS 页面。我仍然无法在 ASP.NET 中启动它。我已经尝试了learn.iis.net/page.aspx/508/… 中的建议,但它们似乎没有效果。我的所有错误处理再次完成,在 global.asax 中我没有为此使用任何自定义模块。看来我只需要一个部分,所以 IIS 不会处理请求。
  • @Kaos - 您的池是在经典还是集成管道模式下运行
  • @Kev 似乎正在工作。下面是我在 Web.config 中所做的。
  • @Kev 你的 sn-p 让我到了那里,但我要发布我的完整解决方案。我想分享我更新的代码,所以如果其他人有类似的问题,他们可以修复它。再次感谢。
【解决方案2】:

IIS 永远不会调用 ASP.NET。 IIS 处理页面请求,发现页面不存在,并且 ASP.NET 永远不会被加载。

如果您希望无论文件是否存在都加载 ASP.NET,您需要更改您的 IIS 配置。您使用的是 IIS6 还是 IIS7/7.5?

【讨论】:

  • 谢谢,我在实时服务器上使用 IIS 7 本地和 IIS 7.5
  • 我如何设置它以便 ASP.net 加载不管
  • 这里是关于处理所有请求的一些信息,IIS7/7.5 信息从页面的中间开始:link 重要的部分在最后;您需要将runAllManagedModulesForAllRequests 设置为True
【解决方案3】:

您需要设置通配符映射,以便所有请求都通过.Net

如果您使用 IIS6,以下链接应该可以帮助您:

http://professionalaspnet.com/archive/2007/07/27/Configure-IIS-for-Wildcard-Extensions-in-ASP.NET.aspx

通配符脚本映射和 IIS 7 集成管道:

http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/

【讨论】:

  • 谢谢我在本地使用 IIS 7,在现场使用 IIS 7.5。
【解决方案4】:

我找不到这方面的源材料,但我认为问题在于它正在处理自定义错误 pagesnot paths时间>。

您的调查表明您遇到了这种情况,因为:

www.mysite.com/nonexistingpath/nonexistingpage.aspx

这应该会点击正确的错误页面。以下不会:

www.mysite.com/nonexistingpath/

这种重申您已经回答了自己的问题,但我会看看是否可以找到参考资料。最终,它不是页面请求,因此没有通过适当的处理程序进行 ISAPI 处理。

【讨论】:

  • 谢谢,我在现场使用 IIS 7 本地和 IIS 7.5。找到材料后告诉我。
  • @Kaos:Crunchy/Charlie 提供的任何链接都没有成功?他们提供如何,即使不是为什么
  • Crunchy/Charlie 提供的链接帮助了一些人,但没有让我找到所需的解决方案。
猜你喜欢
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
  • 2012-11-13
相关资源
最近更新 更多