ASP.NET 2.0: наилучшая практика написания страницы с ошибками - PullRequest
5 голосов
/ 04 августа 2009

На сайте asp.net 2.0, как лучше написать страницу ошибок. Я видел следующий раздел в следующем месте:

Web.Config
<customErrors mode="RemoteOnly" defaultRedirect="~/Pages/Common/DefaultRedirectErrorPage.aspx">

Global.asax
void Application_Error(object sender, EventArgs e) 
{ 
}

Я не понимаю, как наилучшим образом использовать их для обработки ошибок.

Пожалуйста, ведите меня лучше всего.

Ответы [ 2 ]

9 голосов
/ 04 августа 2009

В моем глобальном asax я всегда проверяю, какой тип ошибки http ...

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

Немного информации о коде состояния http важно знать, почему они обрабатываются:

http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

мой web.config выглядит примерно так

<customErrors mode="On"  defaultRedirect="~/error.aspx"  >
  <error statusCode="404" redirect="~/lost.aspx"  />
  <error statusCode="500" redirect="~/error.aspx"  />
</customErrors>

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

моя страница с ошибкой немного отличается, показывая некоторые сообщения об ошибках,

так что я обращаюсь с обоими по-разному.

в зависимости от того, есть ли у вас защищенные области вашего сайта, вы, возможно, захотите справиться с 401/403?

protected void Application_Error(object sender, EventArgs e)
{
    var context = Context;


    var error = context.Server.GetLastError() as HttpException;
    var statusCode = error.GetHttpCode().ToString();

    // we can still use the web.config custom errors information to
    // decide whether to redirect
    var config = (CustomErrorsSection)WebConfigurationManager.GetSection("system.web/customErrors");
    if (config.Mode == CustomErrorsMode.On ||
        (config.Mode == CustomErrorsMode.RemoteOnly && context.Request.Url.Host != "localhost"))
    {
        // set the response status code
        context.Response.StatusCode = error.GetHttpCode();

        // Server.Transfer to correct ASPX file for error
        if (config.Errors[statusCode] != null)
        {

            HttpContext.Current.Server.Transfer(config.Errors[statusCode].Redirect);
        }
        else
            HttpContext.Current.Server.Transfer(config.DefaultRedirect);
    }
}

причина, по которой я передаю данные на сервер, заключается в том, что поисковые системы не запутываются, и чтобы мои журналы веб-мастеров содержали смысл ... если вы перенаправляете, вы возвращаете статус http 302, который говорит браузеру перейти на страницу, перенаправленную на ... затем следующая страница возвращает код состояния 200 (ок).

302 -> 200 или даже 302 -> 404 имеет другое значение, что просто 404 ...

затем, скажем, на моей странице ошибки 404, я должен убедиться, что установил код состояния ошибки http:

protected void Page_PreRender(object sender, EventArgs e)
{
    Response.Status = "404 Lost";
    Response.StatusCode = 404;

}

Эта статья была полезна для меня, я знал, что хочу сделать, но мне нравится, как этот код выглядит в настройках web.config ... http://helephant.com/2009/02/improving-the-way-aspnet-handles-404-requests/

Вернуть правильный код состояния

По умолчанию страница обрабатывает 404 страница ошибки не возвращает статус 404 код для браузера. Он отображает сообщение об ошибке, которое вы предоставили пользователь, но не имеет никаких дополнительных информация для пометки страницы как страница ошибки.

Это называется soft 404. Soft 404 страницы не так хороши, как те, которые вернуть код состояния 404, потому что возврат кода состояния 404 позволяет что-нибудь доступ к вашему файлу, что страница является страницей с ошибкой, а не реальная страница вашего сайта. Это в основном полезно для поисковых систем, потому что тогда они знают, что они должны удалить мертвых страницы из их индекса, чтобы пользователи не следуйте мертвым ссылкам на ваш сайт с страницы результатов.

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

редактирует

Требуется ли написать server.clearerror () в global.asax? На что это влияет

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

Почему в web.config мы должны написать error.aspx дважды один с кодом состояния 500, а другой defaultredirect

  • Я использую 2, потому что потерянная страница должна показать / и делать разные вещи, чем Ошибка сервера. страница ошибки показывает у пользователя произошла ошибка, что мы не мог оправиться от ... и его наверное наша вина. Я оставляю перенаправление по умолчанию для любого другого коды ошибок также. 403 401 400 ( они более редки, но должны быть обработано)

Можете ли вы также сказать мне код error.aspx и lost.aspx.

  • это зависит от типа сайта у тебя есть. вы получаете ошибку то же самое Кстати, но что вы делаете с этим до вы. на моей потерянной странице я ищу некоторый контент, который пользователь мог находясь в поиске. страницы ошибок я регистрирую ошибка и так дружественный упс страница ... вам нужно будет выяснить, что нужно.
3 голосов
/ 22 сентября 2012

Ответ BigBlondeViking отлично работал для меня, за исключением того, что я обнаружил, что он не обрабатывает 403 (который генерирует ASP при попытке прямого доступа к каталогам / Scripts / или / Content /.) таким образом, не может быть перехвачен в обработке Application_Error. (это было определено как «уязвимость безопасности» внешней фирмой - не заставляйте меня начинать с этого!)

protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
    if (!Context.Items.Contains("HasHandledAnError")) // have we alread processed?
    {
        if (Response.StatusCode > 400 &&  // any error
            Response.StatusCode != 401)   // raised when login is required
        {
            Exception exception = Server.GetLastError();    // this is null if an ASP error
            if (exception == null)
            {
                exception = new HttpException((int)Response.StatusCode, HttpWorkerRequest.GetStatusDescription(Response.StatusCode));
            }
            HandleRequestError(exception); // code shared with Application_Error
        }
    }
}

Я также внес небольшое изменение в свою общую обработку ошибок. Поскольку мы используем ASP.NET MVC, я хотел явно вызвать контроллер, а также передать объект исключения. Это позволило мне получить доступ к самому исключению, чтобы я мог регистрировать / отправлять подробные электронные письма в зависимости от кода

public ActionResult ServerError(Exception exception)
{
    HttpException httpException = exception as HttpException;
    if(httpException != null)
    {
        switch (httpException.GetHttpCode())
        {
            case 403:
            case 404:
                Response.StatusCode = 404;
                break;
        }
        // no email...
        return View("HttpError", httpException);
    }
    SendExceptionMail(exception);
    Response.StatusCode = 500;
    return View("ServerError", exception);
}

Чтобы передать исключение ОБЪЕКТ (не только сообщение и код), я явно вызвал контроллер:

protected void HandleRequestError(Exception exception)
{
    if (Context.Items.Contains("HasHandledAnError"))
    {
        // already processed
        return;
    }
    // mark as processed.
    this.Context.Items.Add("HasHandledAnError", true);

    CustomErrorsSection customErrorsSection = WebConfigurationManager.GetWebApplicationSection("system.web/customErrors") as CustomErrorsSection;

    // Do not show the custom errors if
    // a) CustomErrors mode == "off" or not set.
    // b) Mode == RemoteOnly and we are on our local development machine.
    if (customErrorsSection == null || !Context.IsCustomErrorEnabled ||
        (customErrorsSection.Mode == CustomErrorsMode.RemoteOnly && Request.IsLocal))
    {
        return;
    }

    int httpStatusCode = 500;   // by default.
    HttpException httpException = exception as HttpException;
    if (httpException != null)
    {
        httpStatusCode = httpException.GetHttpCode();
    }

    string viewPath = customErrorsSection.DefaultRedirect;
    if (customErrorsSection.Errors != null)
    {
        CustomError customError = customErrorsSection.Errors[((int)httpStatusCode).ToString()];
        if (customError != null && string.IsNullOrEmpty(customError.Redirect))
        {
            viewPath = customError.Redirect;
        }
    }

    if (string.IsNullOrEmpty(viewPath))
    {
        return;
    }

    Response.Clear();
    Server.ClearError();

    var httpContextMock = new HttpContextWrapper(Context);
    httpContextMock.RewritePath(viewPath);
    RouteData routeData = RouteTable.Routes.GetRouteData(httpContextMock);
    if (routeData == null)
    {
        throw new InvalidOperationException(String.Format("Did not find custom view with the name '{0}'", viewPath));
    }
    string controllerName = routeData.Values["controller"] as string;
    if (String.IsNullOrEmpty(controllerName))
    {
        throw new InvalidOperationException(String.Format("No Controller was found for route '{0}'", viewPath));
    }
    routeData.Values["exception"] = exception;

    Response.TrySkipIisCustomErrors = true;
    RequestContext requestContext = new RequestContext(httpContextMock, routeData);
    IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
    IController errorsController = factory.CreateController(requestContext, controllerName);
    errorsController.Execute(requestContext);
}
...