【问题标题】:ASP.NET 2.0 : Best Practice for writing Error PageASP.NET 2.0:编写错误页面的最佳实践
【发布时间】:2010-11-16 16:35:31
【问题描述】:

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

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

  • 全球.asax
    void Application_Error(object sender, EventArgs e) 
    { 
    }
    

  • 我不知道如何以最佳方式使用它们来处理错误。

    请指导我最好的方法。

    【问题讨论】:

    • 你是什么环境? IIS7 还是 IIS6? .net2.0 还是 3.5?
    • 我使用的是 IIS 6、.NET 3.5。有区别吗?
    • 错误 http 模块使用 IIS7 更容易,但你可以使用 IIS6 获得强大的功能,所以不用担心。

    标签: asp.net error-handling global-asax


    【解决方案1】:

    在我的全局 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-handles-404-requests/

    返回正确的状态码

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

    这称为软 404。软 404 页面不如那些 返回 404 状态码,因为 返回 404 状态码让 任何访问您的文件的东西 page 是错误页面而不是 您网站的真实页面。这主要是 对搜索引擎有用,因为那时 他们知道他们应该移除死者 索引中的页面,因此用户不会 从死链接进入您的网站 结果页面。

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

    编辑

    需要写吗 global.asax 中的 server.clearerror()? 有什么影响

    • 不,您可以在错误页面上执行此操作, 不确定影响?如果你做一个 转移非,如果你重定向,那里 可能是另一种可能性 请求之间发生错误? 我不知道

    为什么在 web.config 中我们应该写 error.aspx 两次状态码为 500,另一次为 默认重定向

    • 我使用 2 是因为丢失的页面应该 显示/做与 a 不同的事情 服务器错误。错误页面显示 用户有一个错误,我们 无法从...中恢复过来 可能是我们的错。我留下一个 其他任何一个的默认重定向 错误代码也是如此。 403,401, 400 ( 它们更罕见,但应该是 处理)

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

    • 这取决于网站的类型 你有。你得到同样的错误 方式,但你用它做什么取决于 你。在我丢失的页面上我搜索 用户可能曾经拥有的一些内容 寻找。我记录的错误页面 错误等用户友好的哎呀 页面...您需要弄清楚 需要什么。

    【讨论】:

    • 您好,感谢您提供的好信息。你能告诉我写 Response.Status = "404 Lost"; 有什么好处吗? Response.StatusCode = 404;第二个我们应该在web.config中写两个重定向页面吗?
    • 扩展了一点...看看我添加的一些资源。
    • 谢谢,现在我想我明白为什么 application_error 页面需要 server.transfer 了,这样 getlasterror 就可以在 error.aspx/lost.aspx 中访问了。如果我们没有显式地编写 server.transfer,那么也会显示错误页面,但使用无法访问最后一个错误的 response.redirect。这里我想知道三点(1)是否需要在global.asax中写server.clearerror()?它有什么影响(2)为什么在web.config中我们应该写两次error.aspx,状态码是500,另一个是defaultredirect(3)你能告诉我error.aspx和lost.aspx的代码吗?
    • 不,您可以通过响应重定向获得错误,但是您向客户端返回 302,302 告诉客户端然后转到错误页面......它的额外步骤不是与只返回 1 次的服务器传输一样好...(阅读我链接到的文章...)
    • 您好,先生,我非常感谢您以如此好的方式指导我。随着我阅读您的回复,我的好奇心增加了更多。我有并行阅读微软 msdn。在那里我找到了以下链接msdn.microsoft.com/en-us/library/bb397417.aspx 你能解释一下吗(1)将你的解决方案与微软进行比较(2)据我所知,我发现你的应用程序错误很好,但我在 microsoft 链接上发现了一些好东西? (3) 你能指导我以最好的方式使用它吗?
    【解决方案2】:

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-28
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      • 2018-06-25
      • 2010-09-19
      相关资源
      最近更新 更多