Как отправить код состояния «500» для общей страницы ошибок в IIS? - PullRequest
10 голосов
/ 19 августа 2010

Я использую общую страницу ошибок, используя директиву ASP.NET <customErrors>.

<customErrors mode="On" defaultRedirect="500.html" redirectMode="ResponseRewrite">
</customErrors>

Проблема - при возникновении ошибки эта страница не возвращает HTTP-статус "500".Он равен 200. Таким образом, средства проверки ссылок и пауки не видят каких-либо проблем.

Как я могу отправить статус 500 HTTP вместе со статической страницей 500.html?

Требования:

  • Я должен использовать redirectMode = "ResponseRewrite"
  • Я не могу использовать динамическую страницу, только статический .html.

Ответы [ 6 ]

7 голосов
/ 27 августа 2010

В документации MSDN для элемента customErrors говорится, что он реализован с помощью System.Web.Configuration.CustomErrorsSection. Если для анализа этого класса мы используем .NET Reflector от Red Gate, мы увидим, где этот параметр используется в Framework.

Используется System.Web.UI.Page.HandleError и System.Web.HttpResponse.ReportRuntimeError.

Оба они в конечном итоге вызывают System.Web.HttpResponse.RedirectToErrorPage. (Название этого метода сбивает с толку: важно отметить, что RedirectToErrorPage принимает параметр redirectMode в качестве параметра, поэтому он вызывается, даже если вы используете ResponseRewrite и перенаправление фактически не происходит.)

Соответствующая часть метода RedirectToErrorPage:

    if (redirectMode == CustomErrorsRedirectMode.ResponseRewrite)
    {
        this.Context.Server.Execute(url);
    }

Кажется, нет никакого способа установить код ответа при обработке ошибок: в конце концов, это просто обычный Server.Execute. Поэтому кажется неизбежным, что вам понадобится написать код для получения желаемого HTTP-ответа.

Можете ли вы пересмотреть, почему вы хотите использовать простой файл .html? Это кажется разумным выбором для обработки ошибок, потому что вы не хотите проходить через все накладные расходы на странице .aspx, когда это может вызвать другую ошибку.

Но, возможно, есть какое-то среднее положение, которое будет таким же надежным, как и файл .html?

Например, вы можете создать предварительно скомпилированный HttpHandler, зарегистрировать его по URL-адресу /500.error, а затем сделать 500.error вашей страницей defaultRedirect. (Это будет похоже на работу ScriptResource.axd.) Если вы предварительно скомпилируете свой модуль в DLL (в отличие от компиляции «на лету» из простого старого файла .axd), вы можете обнаружить, что он столь же надежен в лицо ошибочных условий. Если вы столкнулись с ошибкой, из-за которой даже это не сработало, статический файл .html, вероятно, тоже не сработал - имейте в виду, что директива customErrors по-прежнему опирается на .NET, работающую под капотом, и все еще использует StaticFileHandler для обслуживания ваш .html файл.

В качестве альтернативы вы могли бы рассмотреть обратный прокси-сервер перед вашим приложением IIS, который бы обслуживал удобные 500 страниц даже в случае катастрофического сбоя пула приложений. Это будет больше работы для настройки, но будет даже более надежным, чем customErrors, например если ваш web.config будет поврежден, даже customErrors не будет работать.

4 голосов
/ 21 августа 2010

В вашем файле gllobal.asax добавьте следующий код

protected void Application_EndRequest(object sender, EventArgs e)
    {
        if (Request.Url.AbsolutePath.EndsWith("500.html"))
            Response.StatusCode = 500;
    }
3 голосов
/ 25 августа 2010

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

Итак, пример default.aspx

public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        throw new Exception("boom");
    }
}

Затем в файле global.asax:

protected void Application_Error(object sender, EventArgs e)
{
    // Clear the error to take control of process
    Server.ClearError();

    Response.WriteFile(Server.MapPath("500.html"));
    Response.StatusCode = 500;
    Response.StatusDescription = "Internal Server Error";
}

Вероятно, вы можете написать лучший механизм обработки для 500.html часть - я думаю, что это должно сделать то, что вы пытаетесь достичь.

Проверено только с веб-сервером VS Cassini, однако я не вижу причин, почему это не должно работать в iis6.

1 голос
/ 20 августа 2010

Попробуйте настроить свой пользовательский раздел ошибок следующим образом:

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

В своем файле 500.aspx измените код ответа в page_load;

Response.StatusCode = 500;
Response.StatusDescription = "Internal Server Error";
0 голосов
/ 27 августа 2010

Это можно сделать с помощью фильтра isapi. Это должно было бы быть написано в c, но это может изменить статус ответа для запроса .html, чтобы браузер получил 500 с вашей пользовательской HTML-страницей.

0 голосов
/ 26 августа 2010

Если вы настаиваете на изменении базовой HTTP-сигнализации, то вам нужно либо выполнить некоторые требования, либо быть готовым написать собственный веб-сервер. Да, вам нужно запустить интегрированный IIS7 AppPool, и вам все равно, возможно, придется принять перенаправление на активную страницу, поскольку вы пытаетесь имитировать, что ваш сервер не работает, а сервер не предназначен для фальсификации самоубийства. Так что, если это дает вам один тонкий способ сделать это, вы можете либо поблагодарить, либо разработать свой собственный, не совместимый с HTTP сервер, который будет шифровать коды ответов по желанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...