Как нам известно, от, например, В чем разница между customErrors и httpErrors?, CustomErrors - это более старый способ определить страницы ошибок в веб-приложении, но этот подход имеет некоторые проблемы - например, если вы заботитесь о правильных кодах ответов HTTP, поскольку подход CustomErrors - это перенаправление на страницу с ошибкой вместо замены текущего ответа, что уничтожает большую часть семантической целостности сообщения по кодам статуса http.
HttpErrors - это новая функция, доступная с момента запуска IIS 7.0 на уровне сервера, а не уровня приложения. лучше подходит для корректной обработки ответов об ошибках, например, используя текущий ответ вместо перенаправления.
Однако, если мне кажется, что инфраструктура для этих артефактов в ASP.NET, как она выглядит сегодня, дает нам некоторую проблему.
Простая конфигурация в качестве примера
<httpErrors existingResponse="Auto" errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="/Error/E404" responseMode="ExecuteURL" />
</httpErrors>
Мы устанавливаем errorMode для Custom, потому что хотим протестировать само обработку ошибок, и мы устанавливаем существующийResponse в Auto, который вводит ветвь, зависящую от Response.TrySkipIisCustomErrors:
- True: существующий ошибочный ответ пройдет через этот модуль без обработки, что делает полный смысл, учитывая его смысловое значение.
- False: существующий ошибочный ответ будет заменен модулем HttpErrors, если у него есть соответствующее правило, которое имеет такой же смысл.
Это в идеале позволит нам самим обрабатывать некоторые ошибки, например, когда продукт в.. /product/id не существует, где мы можем вручную вернуть конкретную страницу 404 с информацией о недостающих продуктах и допустить, чтобы модуль HttpErrors обрабатывать все остальное, как.. /products/namebutshouldbeid или просто.. /misspelledandunmatchableurl.
Однако, насколько я вижу, это не работает. Причина заключается во внутреннем методе System.Web.HttpResponse.ReportRuntimeError, который будет вызываться при ошибках во время выполнения (например, контроллеры/действия не найдены) и где у нас есть раздел, который выглядит следующим образом:
// always try to disable IIS custom errors when we send an error
if (_wr != null) {
_wr.TrySkipIisCustomErrors = true;
}
if (!localExecute) {
code = HttpException.GetHttpCodeForException(e);
// Don't raise event for 404. See VSWhidbey 124147.
if (code != 404) {
WebBaseEvent.RaiseRuntimeError(e, this);
}
// This cannot use the HttpContext.IsCustomErrorEnabled property, since it must call
// GetSettings() with the canThrow parameter.
customErrorsSetting = CustomErrorsSection.GetSettings(_context, canThrow);
if (customErrorsSetting != null)
useCustomErrors = customErrorsSetting.CustomErrorsEnabled(Request);
else
useCustomErrors = true;
}
Во время первой отладки я увидел, что useCustomErrors был установлен в false, и я не мог понять, почему, поскольку я знал, что у меня есть рабочая конфигурация HttpError, поскольку она работает там, где я возвращаю HttpNotFoundResult с контроллера.
Тогда я понял, что это не HttpErrors, а более старые CustomErrors. И CustomErrors, очевидно, не знает HttpErrors.
"ошибка"
Итак, происходит то, что Response.TrySkipIisCustomErrors имеет значение true, и поскольку никакие параметры CustomErrors не определены, он возвращает подробный ответ 404. На этом этапе мы хотели бы, чтобы HttpErrors набрали, но это не из-за TrySkipIisCustomErrors теперь установлено в true.
И мы также не можем использовать CustomErrors, так как это вернет нас к проблемам с перенапряжением ошибок.
И причина, по которой возвращается HttpNotFoundResult, заключается в том, что она не выведет ошибку времени выполнения, а возвращает только 404-результат, который HttpErrors будет перехватываться, как ожидалось, до тех пор, пока мы избежим установки Response.TrySkipIisCustomErrors в true.
Как это должно быть/разрешено/разрешено?
Я думаю, что System.Web.HttpResponse.ReportRuntimeError не должно быть разрешено устанавливать Response.TrySkipIisCustomErrors до true по умолчанию, так как у нас есть другой модуль обработки ошибок, зависящий от этого. Таким образом, этот метод должен знать любую конфигурацию HttpErrors, либо если вы не установите для параметра TrySkipIisCustomErrors значение true, если у нас есть CustomErrors или что он обрабатывает конфигурацию HttpErrors вместе с конфигурацией CustomErrors.
Или я пропустил какую-то секретную магию, чтобы решить эту проблему?