5

在 asp.net 2.0 网站中,编写错误页面的最佳方式是什么。我在以下位置看到了以下部分:

  • 网络配置

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

  • 全球.asax

    void Application_Error(object sender, EventArgs e) 
    { 
    }
    

  • 我没有得到如何以最佳方式使用它们来处理错误。

    请指导我最好的方法。

    4

    2 回答 2

    9

    在我的全局 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 ( ok )。

    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-处理 404 请求/

    返回正确的状态码

    默认情况下,处理 404 错误页面的页面不会向浏览器返回 404 状态代码。它显示您提供给用户的错误消息,但没有任何额外信息将该页面标记为错误页面。

    这称为软 404。软 404 页面不如返回 404 状态码的页面好,因为返回 404 状态码会让任何访问您的文件的人认为该页面是错误页面,而不是您网站的真实页面。这对搜索引擎最有用,因为他们知道应该从索引中删除死页,这样用户就不会从结果页中将死链接跟踪到您的网站。

    返回 404 状态代码的页面对于错误检测也很有用,因为它们会记录在您的服务器日志中,因此如果您遇到意外的 404 错误,很容易找到它们。以下是 Google 网站管理员工具中的 404 错误报告示例:

    编辑

    是否需要在 global.asax 中编写 server.clearerror() ?它有什么影响

    • 不,您可以在错误页面上执行此操作,不确定影响?如果您进行非传输,如果您重定向,请求之间可能会发生另一个错误?我不知道

    为什么在 web.config 中我们应该写两次 error.aspx,一次是状态码 500,另一次是 defaultredirect

    • 我使用 2 是因为丢失的页面应该显示/并执行与服务器错误不同的操作。错误页面向用户显示我们无法从中恢复的错误......这可能是我们的错。我也为任何其他错误代码保留了默认重定向。403,401、400(它们比较少见,但应该处理)

    能否也告诉我error.aspx和lost.aspx的代码。

    • 这取决于您拥有的网站类型。你会以同样的方式得到错误,但你如何处理它取决于你。在我丢失的页面上,我搜索用户可能一直在寻找的一些内容。错误页面我记录了错误,因此是一个用户友好的 oops 页面……您需要弄清楚需要什么。
    于 2009-08-04T13:58:20.497 回答
    3

    BigBlondeViking 的响应对我很有效,只是我发现它没有处理 403(当您尝试直接访问 /Scripts/ 或 /Content/ 目录时 ASP 会生成该响应)。看来这不是作为异常传播的,因此不可捕获在 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);
    }
    

    为了传递异常 OBJECT(不仅仅是消息和代码),我显式调用了控制器:

    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);
    }
    
    于 2012-09-21T20:39:02.550 回答