Как реализовать правильную обработку ошибок HTTP in.NET MVC 2?
я боролся весь день, чтобы реализовать обработку ошибок в моем ASP.NET MVC 2 app. Я просмотрел множество методов, но ни один из них не работает должным образом. Я использую MVC2 и .NET 4.0 (начал проект до того, как MVC3 был выпущен; мы будем обновляться после того, как мы доставим наш первоначальный выпуск).
на данный момент я буду рад правильно обрабатывать 404 и 500 ошибок-403 (требуется авторизация) тоже было бы здорово, а затем различные другие конкретные ответы. Прямо сейчас, я вам все 404, все 500, все 302 до 404 или все 302 до 500.
вот мои требования (которые должны быть довольно близки к основным требованиям HTTP):
если ресурс не найден, бросьте 404 и отобразите страницу 404 с запрошенным URL-адресом. Не возвращайте промежуточный код ответа, например 302. В идеале сохраните запрошенный URL, а не показывать новый URL, как
/Error/NotFound
-- но если последнее отображается, убедитесь, что мы этого не делали верните ответ перенаправления, чтобы получить его.если произошла внутренняя ошибка сервера, бросьте 500 и отобразите 500-конкретную ошибку с некоторым указанием того, что пошло не так. Опять же, не возвращайте промежуточный код ответа и в идеале не меняйте URL-адрес.
вот что я считаю 404:
- статический файл не найден:
/Content/non-existent-dir/non-existent-file.txt
- контроллер не нашел:
/non-existent-controller/Foo/666
найдено, но действие не найдено: - контроллер и действие, но действие не может найти запрошенный объект:
/Home/Login/non-existent-id
/Home/non-existent-action/666
вот что я бы назвал 500:
- сообщение плохое значение:
POST /User/New/new-user-name-too-long-for-db-column-constraint
- проблема, не связанная с данными, например, конечная точка веб-службы не отвечает
некоторые из этих проблем должны быть определены конкретными контроллерами или моделями, а затем контроллеры должны бросить соответствующее исключение HttpException. С остальными следует обращаться более обобщенно.
для случая 404 #2 я попытался использовать пользовательский ControllerFactory, чтобы бросить 404, если контроллер не может быть найден.
Для случая 404 #3 я попытался использовать пользовательский базовый контроллер для переопределения HandleUnknownAction
и бросить 404.
в обоих случаях я получаю 302 до 404. И я никогда не получаю 500 ошибок; если я изменяю Web.config чтобы поместить опечатку в мою конечную точку веб-службы, я все еще получаю 302, а затем 404, говорящий URL (контроллер / действие) который использует веб-служба не может быть найден.
Я также получаю запрошенный URL-адрес как (N нежелательный) querystring param:/Error/NotFound?aspxerrorpath=/Home/non-existent-action
оба эти метода пришли из http://www.niksmit.com/wp/?p=17 (Как получить обычные 404 (страница не найдена) страницы ошибок с помощью ASP.Net MVC), указал на from http://richarddingwall.name/2008/08/17/strategies-for-resource-based-404-errors-in-aspnet-mvc/
если в Сеть.config у меня есть <customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" />
, Я получаю соответствующий код ответа, но мой контроллер ошибок не вызывается. Вынимая redirectMode
атрибут возвращает мне представления ошибок MVC, но с промежуточным 302 и измененным URL-адресом-и всегда один и тот же контроллер (Unknown
= 500; если я изменю его на NotFound
все выглядит как 404).
вот некоторые из других вещей, которые я читал и пытался вместе с кучей сообщений StackOverflow.
мне кажется, что такого рода обработка ошибок довольно проста для веб-приложений, и структура MVC должна иметь значения по умолчанию, которые делают это из коробки, и пусть люди расширяют ее для работы в противном случае. Возможно, они сделают это в будущем. Тем временем, может ли кто-нибудь дать мне исчерпывающие сведения о том, как реализовать правильные ответы HTTP?
4 ответов
вот один метод, который вы могли бы использовать. Определите ErrorsController
который будет обслуживать страницы ошибок:
public class ErrorsController : Controller
{
public ActionResult Http404()
{
Response.StatusCode = 404;
return Content("404", "text/plain");
}
public ActionResult Http500()
{
Response.StatusCode = 500;
return Content("500", "text/plain");
}
public ActionResult Http403()
{
Response.StatusCode = 403;
return Content("403", "text/plain");
}
}
и затем в Global.asax
вы можете подписаться на Application_Error
событие, в котором вы можете зарегистрировать исключение и выполнить соответствующее действие ErrorsController
:
protected void Application_Error(object sender, EventArgs e)
{
var app = (MvcApplication)sender;
var context = app.Context;
var ex = app.Server.GetLastError();
context.Response.Clear();
context.ClearError();
var httpException = ex as HttpException;
var routeData = new RouteData();
routeData.Values["controller"] = "errors";
routeData.Values["exception"] = ex;
routeData.Values["action"] = "http500";
if (httpException != null)
{
switch (httpException.GetHttpCode())
{
case 404:
routeData.Values["action"] = "http404";
break;
case 403:
routeData.Values["action"] = "http403";
break;
case 500:
routeData.Values["action"] = "http500";
break;
}
}
IController controller = new ErrorsController();
controller.Execute(new RequestContext(new HttpContextWrapper(context), routeData));
}
и теперь все, что осталось-это начать бросать правильные исключения:
public class HomeController : Controller
{
public ActionResult Index()
{
throw new HttpException(404, "NotFound");
}
}
для ошибок HTTP 404 (без перенаправления) взгляните на мое сообщение в блоге по этому вопросу. Это может дать вам некоторые хорошие идеи:
http://hectorcorrea.com/blog/returning-http-404-in-asp-net-mvc/16
Это не отвечает на ваш вопрос, но важно отметить, что HTTP status 500 указывает, что что-то пошло не так на сервере, поэтому ваш пример:
POST /User/New/new-user-name-too-long-for-db-column-constraint
не является допустимым основанием для создания 500, его проблема проверки данных и должна обрабатываться аннотациями данных MVC или платформой проверки jQuery или т. д. Просто показывая сообщение об ошибке рядом с текстовым полем, говоря "имя пользователя слишком долго" намного лучше.
Это очень старый вопрос. но я подумал, что это стоит того, если я познакомлю вас с гораздо более чистым способом обработки исключений Http, которые я видел в dear "ответ Джесси Уэбба".
решение заключается в использовании httpErrors
элемент :
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
<error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>
вы также можете регистрировать все исключения таким образом. - Прочти "ответ Джесси Уэбба"".
Это действительно чувствует себя намного чище, а также работает, а также каждый другой решение (без перенаправления).
Примечание: это работает только в IIS 7 и новее. (Из-за httpErrors
элемент, который был недавно добавлен.