ASP.NET Custom 404 Возврат 200 OK вместо 404 не найден

После попытки настроить мой сайт для Инструментов Google для веб-мастеров, я обнаружил, что моя пользовательская страница ASP.NET 404 не возвращала код статуса 404. Он отобразил правильную страницу и сказал браузеру, что все в порядке. Это считается мягким 404 или ложным 404. Google не нравится это. Поэтому я нашел много статей по этой проблеме, но решение, которое я хочу, похоже, не работает.

Решение, которое я хочу использовать, заключается в добавлении следующих двух строк в код, стоящий за методом Page_Load на пользовательской странице 404.

Response.Status = "404 Not Found";
Response.StatusCode = 404;

Это не работает. Страница все еще возвращает 200 OK. Однако я обнаружил, что если я буду жестко закодировать следующий код в код проекта, он будет работать правильно.

<asp:Content ID="ContentMain" ContentPlaceHolderID="ContentPlaceHolderMaster" runat="server">

<%
    Response.Status = "404 Not Found";
    Response.StatusCode = 404;
%>

 ... Much more code ...

</asp:content>

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

Ответ 1

Решение:

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

protected override void Render(HtmlTextWriter writer)
{
    base.Render(writer);
    Response.StatusCode = 404;
}

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


Оригинальное сообщение:

Мне удалось заставить тестовое веб-приложение работать нормально, ну, по крайней мере, он отобразил страницу пользовательских ошибок и вернул код статуса 404. Я не могу сказать вам, что не так с вашим приложением, но я могу сказать вам, что я сделал:

1) Отредактировано web.config для пользовательских ошибок:

<customErrors mode="On">
  <error statusCode="404" redirect="404.aspx"/>
</customErrors>

2) Добавлена ​​страница 404.aspx и установите код состояния 404.

public partial class _04 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.StatusCode = 404;
    }
}

Вот и все, если я перейду к любому расширению страницы, которое обрабатывается Asp.Net и не существует, в моем журнале fiddler явно отображается 404, вот заголовок:

HTTP/1.1 404 Not Found
Server: Microsoft-IIS/5.1
Date: Sun, 07 Dec 2008 06:04:13 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 533

Теперь, если я перейду на страницу, которая не обрабатывается Asp.Net, например, файл htm, пользовательская страница не отображается и отображается 404, настроенная IIS.

Вот сообщение, в котором вы найдете более подробную информацию, которая может быть полезной для вас и вашей проблемы, мой тест делает перенаправление на новую страницу, поэтому URL-адрес запрашиваемого файла в значительной степени теряется (кроме его в строка запроса).

Пользовательские страницы ошибок Google 404 и .NET

Ответ шпиона шлейфа:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT

Ответ 2

У меня была аналогичная проблема: я хочу показать пользовательскую страницу как 404 (это ASPX), и она отлично работала на localhost, но как только удаленный посетитель подключился, они получат общий IIS 404.

Решением этого было добавить

Response.TrySkipIisCustomErrors = true;

Перед изменением кода Response.StatusCode.

Найдено через Рик Страл http://www.west-wind.com/weblog/posts/745738.aspx

Ответ 3

Решение IIS 7 должно просто добавить это в ваш файл web.config:

<system.webServer>
  <httpErrors existingResponse="Replace">
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" prefixLanguageFilePath="" path="404.htm" responseMode="File" />
    <error statusCode="500" prefixLanguageFilePath="" path="500.htm" responseMode="File" />
  </httpErrors>
</system.webServer>

http://forums.asp.net/t/1563128.aspx/1

Ответ 4

Попробуйте вызвать Response.End(), чтобы пропустить рендеринг...

Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;

Ответ 5

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

<%
// This code is required for host that do special 404 handling...
Response.Status = "404 Not Found";
Response.StatusCode = 404;
%>

Это позволит странице вернуть правильный код возврата независимо от того, что.

Ответ 6

Мне удалось обойти эту проблему, используя следующую настройку в веб-форматах asp.net с помощью .NET 3.5.

Образец, который я реализовал, обходит .NET custom redirect solution в web.config, поскольку я написал свой собственный, чтобы обрабатывать все сценарии с правильным кодом статуса HTTP в заголовке.

Сначала раздел customErrors web.config выглядит следующим образом:

<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />

Эта настройка гарантирует, что режим CustomErrors включен, параметр, который нам понадобится позже, и предоставит параметр all-else-fail для defaultRedirect error.htm. Это пригодится, если у меня нет обработчика конкретной ошибки или что-то похожее на сломанное соединение с базой данных.

Во-вторых, здесь глобальное событие asax Error:

protected void Application_Error(object sender, EventArgs e)
    {
       HandleError();
    }

    private void HandleError()
    {
        var exception = Server.GetLastError();
        if (exception == null) return;

        var baseException = exception.GetBaseException();

        bool errorHandled = _applicationErrorHandler.HandleError(baseException);
        if (!errorHandled) return;


        var lastError = Server.GetLastError();
    if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
        Server.ClearError();
    }
    }

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

Класс applicationErrorHandler выглядит следующим образом:

public bool HandleError(Exception exception)
        {
            if (exception == null) return false;

            var baseException = exception.GetBaseException();

            Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);

            if (!HttpContext.Current.IsCustomErrorEnabled) return false;

            try
            {

                var behavior = _responseBehaviorFactory.GetBehavior(exception);
                if (behavior != null)
                {
                    behavior.ExecuteRedirect();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
            }
            return false;
        }

Этот класс по существу использует шаблон команды, чтобы найти соответствующий обработчик ошибок для типа выданной ошибки. Важно использовать Exception.GetBaseException() на этом уровне, потому что почти каждая ошибка будет обернута в исключение более высокого уровня. Например, выполнение "throw new System.Exception()" с любой страницы aspx приведет к получению HttpUnhandledException на этом уровне, а не к System.Exception.

Код "factory" прост и выглядит следующим образом:

public ResponseBehaviorFactory()
    {
        _behaviors = new Dictionary<Type, Func<IResponseBehavior>>
                        {
                            {typeof(StoreException), () => new Found302StoreResponseBehavior()},
                            {typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
                            {typeof(HttpException), () => new HttpExceptionResponseBehavior()},
                            {typeof(Exception), () => new Found302DefaultResponseBehavior()}
                        };
    }

    public IResponseBehavior GetBehavior(Exception exception)
    {                                                                               
        if (exception == null) throw new ArgumentNullException("exception");

        Func<IResponseBehavior> behavior;
        bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);

        //default value here:
        if (!tryGetValue)
            _behaviors.TryGetValue(typeof(Exception), out behavior);

        if (behavior == null)
            Elmah.ErrorSignal.FromCurrentContext().Raise(
                new Exception(
                    "Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
                    exception));
        return behavior();
    }

В конце концов, у меня есть расширяемая схема обработки ошибок. В каждом из определенных "вариантов поведения" у меня есть специальная реализация для типа ошибки. Например, исключение Http будет проверяться для кода состояния и обрабатываться соответствующим образом. Код статуса 404 потребует Server.Transfer вместо Request.Redirect вместе с соответствующим кодом состояния, записанным в заголовке.

Надеюсь, что это поможет.

Ответ 7

Вы можете использовать следующий код:

 Response.TrySkipIisCustomErrors = True
 Response.Status = "404 Not Found"
 Response.AddHeader("Location", "{your-path-to-your-404-page}")