Пользовательская обработка ошибок в web.config / Global.asax не обрабатывает несуществующий каталог - PullRequest
8 голосов
/ 14 апреля 2011

Вопрос: почему пользовательская обработка ошибок не работает для несуществующих путей / каталогов?

Обновлено с исправленным кодом (спасибо всем за ваш вклад):

* Обновлен код для 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.config и global.asax (настройка показана ниже). Мы можем справиться со всеми 404 и 500 без проблем. Ошибки фиксируются в Application_Error в global.asax, регистрируются в БД, затем с помощью 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);
            }
        }
    }
}

Ответы [ 4 ]

25 голосов
/ 14 апреля 2011

Из этого комментария к Мистеру Разочарование:

Спасибо, я использую локальный IIS 7 и IIS 7.5 в прямом эфире.Сообщите мне, когда найдете материал.

Если ваше приложение работает в пуле приложений, настроенном для работы в режиме классического конвейера, то содержимое, не предназначенное для ASP.NET, не попадет в ASP.NETво время выполнения.т.е. папки, которые не существуют.Они будут обрабатываться непосредственно IIS.

У вас есть пара вариантов:

  1. Установите пул приложений в режим интегрированного конвейера.Вам также может понадобиться настроить следующий параметр, если обработка ошибок IIS «съедает» ваш код состояния ASP.NET 404 и 500 из ASP.NET:

    <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, чтобытакие запросы попадают в конвейер.Это было бы неоптимальным решением.

4 голосов
/ 14 апреля 2011

ASP.NET никогда не вызывается IIS.IIS обрабатывает запрос страницы, видит, что страница не существует, и ASP.NET никогда не загружается.

Если вы хотите, чтобы ASP.NET загружался независимо от того, существует ли файл, вам нужно изменитьКонфигурация IIS.Используете ли вы IIS6 или IIS7 / 7.5?

3 голосов
/ 14 апреля 2011

Вам необходимо настроить сопоставление с подстановочными знаками, чтобы все запросы проходили через .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/

0 голосов
/ 14 апреля 2011

Я не могу найти исходный материал для этого, но я считаю, что проблема заключается в том, что он обрабатывает пользовательские ошибки страниц и не путей .

Ваше расследование предполагает, что вы сталкивались с этим, поскольку:

www.mysite.com/nonexistingpath/nonexistingpage.aspx

Это должно появиться на правильной странице ошибки.Следующее не будет:

www.mysite.com/nonexistingpath/

Этот тип повторяет, что вы уже отвечаете на свой вопрос, но я посмотрю, смогу ли я найти справочный материал.В конечном счете, это не запрос страницы, поэтому ISAPI не обрабатывает соответствующие обработчики.

...