IIS7 переопределяет customErrors при установке Response.StatusCode?

98

Здесь странная проблема. Всем известно, что если вы используете customErrorsраздел web.config для создания настраиваемой страницы ошибок, вы должны установить Response.StatusCodeвсе , что вам подходит. Например, если я создам настраиваемую страницу 404 и назову ее 404.aspx, я могу вставить <% Response.StatusCode = 404 %>содержимое, чтобы у нее был настоящий заголовок статуса 404.

Следуй за мной так далеко? Хорошо. Теперь попробуйте сделать это на IIS7. Я не могу заставить его работать, и точка. Если Response.StatusCodeон установлен на настраиваемой странице ошибок, IIS7, похоже, полностью переопределяет настраиваемую страницу ошибок и показывает собственную страницу состояния (если она у вас настроена).

Кто-нибудь еще видел такое поведение и, возможно, знает, как его обойти? Он работал под IIS6, поэтому я не знаю, почему все изменилось.

Примечание: это не то же самое, что проблема в ASP.NET Custom 404 Returning 200 OK вместо 404 Not Found

Николай
источник
У меня такой же вопрос. Уже ответил здесь http://stackoverflow.com/questions/347281/asp-net-custom-404-returning-200-ok-instead-of-404-not-found .
Бобби Кэннон,
Бобби, я действительно нашел этот вопрос и попробовал, но это не помогло. Но спасибо.
Николас
Я хотел бы отметить, что эта проблема также возникает при переходе с классической системы на интегрированную. Я использовал решение @PavelChuchuva (решение @RickStrahl тоже работает). Я предполагаю, что "сквозной переход" в Classic выполняется автоматически, в Integrated это требует обработки глобальной страницы ошибок сервера ..
sonjz

Ответы:

116

Установите для existingResponse значение PassThrough в разделе system.webServer / httpErrors:

  <system.webServer>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>

Значение по умолчанию для свойства existingResponse - Auto:

Авто сообщает настраиваемому модулю ошибок, что нужно делать правильно . Фактический текст ошибки, видимый клиентами, будет изменен в зависимости от значения fTrySkipCustomErrors, возвращаемого при IHttpResponse::GetStatusвызове. Когда для fTrySkipCustomErrors установлено значение true, пользовательский модуль ошибок пропускает ответ, но если для него установлено значение false, пользовательский модуль ошибок заменяет текст своим собственным текстом.

Дополнительные сведения: чего ожидать от настраиваемого модуля ошибок IIS7

Павел Чучува
источник
3
Обратите внимание, что установка параметра existingResponse на PassThrough может привести к некоторым побочным эффектам. Перед любыми изменениями, пожалуйста, усвойте ссылку, предоставленную Павлом.
Лекс Ли,
Является ли <httpErrors existingResponse="PassThrough" />эквивалент Response.TrySkipIisCustomErrorsили же они ведут себя по- другому?
Asbjørn Ulsberg
1
@sbjornu Они достигают того же, но с Response.TrySkipIisCustomErrorsвами лучше контролировать, когда отображать пользовательские ошибки IIS.
Павел Чучува
спасибо, я видел много информации о response.tryskipiiscustomerrors, но не столько о существующем ответе.
HBCondo,
Я решил проблему с настраиваемыми страницами ошибок, которые не работают на моем веб-узле, на котором запущен IIS7, просто установив existingResponse = "Auto", что было очень удивительно, поскольку в статье утверждается, что это значение по умолчанию. Ясно, что это не так ... или я полагаю, что моя хостинговая компания установила неправильное значение по умолчанию в другом месте. В любом случае, я надеюсь, что это сэкономит кому-то несколько часов: \
Эрик Сассаман
80

Самый простой способ сделать поведение согласованным - сбросить ошибку и использовать Response.TrySkipIisCustomErrors и установить для него значение true. Это переопределит обработку страницы глобальной ошибки IIS на вашей странице или глобальный обработчик ошибок в Application_Error.

Server.ClearError();
Response.TrySkipIisCustomErrors = true;

Обычно это следует делать в обработчике Application_Error, который обрабатывает все ошибки, которые обработчики ошибок приложения не улавливают.

Более подробную информацию можно найти в этом сообщении блога: http://www.west-wind.com/weblog/posts/745738.aspx

Рик Страл
источник
2
Это также не работает для меня (IIS8), и совет, похоже, не соответствует OP (при условии, что я правильно его читаю). Я хочу, чтобы customErrorсработало настроенное в Web.config. С Response.TrySkipIisCustomErrors = trueя получаю такое же поведение: отображаются Уродливые сервер сгенерированных страниц ошибок. При его установке falseничего не происходит - пустое окно браузера.
Шон Саут
У меня отлично заработало! Хотя настройка, о которой Павел Чучува упоминает в своем ответе, также работала, у нее были некоторые побочные эффекты, которые вызвали другие проблемы. Этот параметр позволяет мне пропустить переопределение ошибки IIS в конкретном сценарии, который я хотел, оставив при этом поведение для всего остального.
Кевин Тиге
Хорошо работал у меня в Azure. Заголовки сервераServer:Microsoft-IIS/8.5 X-AspNet-Version:4.0.30319 X-AspNetMvc-Version:5.2 X-Powered-By:ASP.NET
oxfn 05
Я все еще считаю, что мне нужно настроить, customErrors mode="Off"чтобы это работало. Если я это сделаю, то httpErrors existingResponse = "Auto" (по умолчанию) будет работать у меня правильно, когда я использую код из этого ответа.
AaronLS
11

Решено: оказывается, что «Подробные ошибки» должны быть включены, чтобы IIS7 мог «пропустить» любую страницу с ошибкой, которая у вас может быть. См. Http://forums.iis.net/t/1146653.aspx

Николай
источник
1
Хотя этот был отмечен как ответ, я думаю, что стоит потратить время на то, чтобы прочитать другие ответы, чтобы получить больше информации по теме.
Лекс Ли,
Также можно было бы удалить. HandleErrorAttribute в FilterConfig
Per G
4

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

Прежде всего, значение по умолчанию для existingResponse (Auto) было правильным ответом в моем случае, поскольку у меня есть собственные 404, 400 и 500 (я мог бы создать другие, но этих трех будет достаточно для того, что я делаю). Вот соответствующие разделы, которые мне помогли.

Из web.config:

<customErrors mode="Off" />

И

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>

Оттуда я добавил это в Application_Error на global.asax:

    Response.TrySkipIisCustomErrors = True

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

Во всяком случае, вот как я это сделал. Надеюсь, это кому-то поможет.

SEFL
источник
3

Эта проблема была большой головной болью. Ни одно из ранее упомянутых предложений само по себе не решило эту проблему, поэтому я включаю свое решение. Для справки, наша среда / платформа использует:

  • .NET Framework 4
  • MVC 3
  • IIS8 (рабочая станция) и IIS7 (веб-сервер)

В частности, я пытался получить ответ HTTP 404, который перенаправлял бы пользователя на нашу настраиваемую страницу 404 (через настройки Web.config).

Во-первых, мой код должен был создать файл HttpException. Возврат a NotFoundResultс контроллера не дал тех результатов, которые мне нужны.

throw new HttpException(404, "There is no class with that subject");

Тогда я должен был Configure какcustomErrors и httpErrorузлов в Web.config.

<customErrors mode="On" defaultRedirect="/classes/Error.aspx">
  <error statusCode="404" redirect="/classes/404.html" />
</customErrors>

...

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/classes/404.aspx" responseMode="ExecuteURL" />
</httpErrors>

Обратите внимание, что я оставил existingResponseas Auto, который отличается от предоставленного решения @sefl.

Эти customErrorsпараметры оказались необходимы для обработки моего явно брошено HttpException, а httpErrorsузел обрабатывается URL - адреса , которые выпадали из шаблонов маршрутов , указанных в Globals.asax.cs.

PS С этими настройками ставить не нужно Response.TrySkipIisCustomErrors

Шон Саут
источник
2

TrySkipIisCustomErrorsэто только часть головоломки. Если вы используете настраиваемые страницы ошибок, но также хотите доставить некоторый контент RESTful на основе статусов 4xx, у вас есть проблема. Установка httpErrors.existingResponse web.config на «Авто» не работает, потому что .net, кажется, всегда доставляет некоторое содержимое страницы в IIS, поэтому использование «Авто» приводит к тому, что все (или, по крайней мере, некоторые) пользовательские страницы ошибок не используются. Использование «Заменить» тоже не сработает, потому что ответ будет содержать ваш код статуса http, но его содержимое будет пустым или заполнено страницей пользовательской ошибки. А «PassThrough» фактически отключает CEP, поэтому его нельзя использовать.

Поэтому, если вы хотите обойти CEP в некоторых случаях (под обходом я имею в виду возврат статуса 4xx с некоторым содержимым), вам понадобится дополнительный шаг: очистите ошибку:

void Application_Error(object sender, EventArgs e)
{
    var httpException = Context.Server.GetLastError() as HttpException;
    var statusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;

    Context.Server.ClearError();
    Context.Response.StatusCode = statusCode;
}

Поэтому, если вы хотите использовать ответ REST (например, 400 - Bad Request) и отправлять с ним некоторый контент, вам просто нужно будет TrySkipIisCustomErrorsгде-то установить действие и установить existingResponseзначение «Auto» в разделе httpErrors в web.config. Сейчас:

  • когда нет ошибки (действие возвращает 4xx или 5xx) и возвращается некоторый контент, CEP не используется, и контент передается клиенту;
  • когда возникает ошибка (создается исключение), содержимое, возвращаемое обработчиками ошибок, удаляется, поэтому используется CEP.

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

Лукас Фрончик
источник
0

По умолчанию IIS 7 использует подробные настраиваемые сообщения об ошибках, поэтому я предполагаю, что Response.StatusCode будет равно 404.XX, а не просто 404.

Вы можете настроить IIS7 для использования более простых кодов сообщений об ошибках или изменить свой код, обрабатывающий более подробные сообщения об ошибках, которые предлагает IIS7.

Дополнительная информация доступна здесь: http://blogs.iis.net/rakkimk/archive/2008/10/03/iis7-enables-custom-error-pages.aspx

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

нулевой
источник
Response.StatusCode - целое число, поэтому я не вижу способа установить более конкретный код, чем просто «404». У меня IIS7 настроен на использование / отображение пользовательских страниц ошибок, как указывает ваш URL.
Николас
Хммм ... К сожалению, сейчас я не могу протестировать, так как я не на своем домашнем компьютере. Если к тому времени у вас не будет решения - я посмотрю сегодня вечером.
nullnvoid