zoukankan      html  css  js  c++  java
  • 028-全局错误处理

    全局文件Global.asax

    添加Web→全局应用程序类,注意文件名不要改。
    全局文件是对Web应用生命周期的一个事件响应的地方
    将Web应用启动时初始化的一些代码写到Application_Start中。应用关闭的时候Application_End调用。
    当一个Session启动的时候Session_Start被调用,Session结束(用户主动退出或者超时结束)Session_End被调用。
    当一个用户请求来的时候Application_BeginRequest方法被调用
    当应用中出现未捕获异常,Application_Error被调用(常考,ASP.Net中的错误处理机制),用HttpContext.Current.Server.GetLastError()获得异常信息,然后用Log4Net记录到日志中。
    案例练习1:屏蔽指定的IP地址(Application_BeginRequest)。
    案例练习2:实现简单url重写。无Cookie实现Session、伪静态Seo。(Application_BeginRequest,在第8个事件之前都可以做url重写,因为在第7个事件之后才会使用url)
    基本思路:
    1.通过正则分析url。
    2.HttpContext.Current.RewritePath("~/ContactsList.aspx");//不是Response.Redirect();

    另一种方式
    HttpContext.Current.RemapHandler(new 页面对象());//如果在Application_BeginRequest事件中已经这么做了,那么意味着在BeginRequest中已经创建了页面对象,那么在HttpApplication的第7个事件后就不再创建页面对象了。

    图片防盗链发过去一个错误图片同样浪费资源。

     1     protected void Application_BeginRequest(object sender, EventArgs e)
     2     {
     3         var Request = HttpContext.Current.Request;
     4         if (Request.Url.PathAndQuery.StartsWith("/domDemo2/images/mm/"))//防止美女时钟的图片盗链
     5         {
     6             //判断是否盗链
     7             if (Request.UrlReferrer == null || !IsSameHost(Request.UrlReferrer, Request.Url))
     8             {
     9                 HttpContext.Current.Response.Write("请勿直接访问图片,请在美女时钟页面中访问!");
    10                 HttpContext.Current.Response.End();
    11             }
    12         }
    13     }
    14 
    15     /// <summary>
    16     /// 判断uri1和uri2是否是在同一台主机上
    17     /// </summary>
    18     /// <param name="uri1"></param>
    19     /// <param name="uri2"></param>
    20     /// <returns></returns>
    21     private static bool IsSameHost(Uri uri1, Uri uri2)
    22     {
    23         return Uri.Compare(uri1, uri2, UriComponents.Host, UriFormat.SafeUnescaped, StringComparison.CurrentCultureIgnoreCase) == 0;
    24     }

    错误页

    当页面发生错误的时候,ASP.Net会将错误信息展示出来(Sqlconnection的错误就能暴露连接字符串),这样一来不好看,二来会泄露网站的内部实现信息,给网站带来安全隐患,因此需要定制错误页,发生错误时显示开发人员定制的页面。404页面放点广告也是好的嘛。
    配置web.config,配置customErrors区域:

    1   <customErrors mode="On" defaultRedirect="MyErrorPage.aspx">
    2     <error statusCode="403" redirect="NoAccess.htm" />
    3     <error statusCode="404" redirect="FileNotFound.htm" />
    4   </customErrors>

    mode三个可选值:On:总是显示定制错误页面;Off:不显示定制错误界面,直接显示调用堆栈等异常信息;remoteonly:对于本机的访问显示调用堆栈等异常信息,对于外部用户的显示定制错误页面。一般设置为RemoteOnly,这样发生错误的话,管理员可以在服务器的浏览器中看详细错误信息,普通用户看不到。学习演示的时候mode设置为On,否则看不到定制页。

    全局错误处理
    -》在全局应用程序类中为事件Application_Error添加处理代码
    -》当出错时,应该做什么呢?
    事务一:记录
    事务二:转到友好提示页面
    -》实现记录
    定义帮助类,完成持久化存储
    问题:如果同时发生多个错误,则写操作都去抢占文件会记录错误信息
    解决:加锁
    新问题:用户等待时间太长
    新解决:将错误写到队列中,再开新线程将队列中的信息写到文件中
    -》最终实现:定义日志帮助类,两个方法
    方法一:用于向队列中写信息,出错时调用
    方法二:用于将队列中的信息写到文件中,在静态构造方法中调用
    -》说明:将日志文件生成到App_Code文件夹下,这样浏览者就无法通过浏览器访问了
    -》问题的关键
    《1》为什么要加锁:每个浏览器的请求,都开启一个线程进行处理
    《2》为什么要向内存中写:向文件中写加锁后用户会等待很长时间
    -》通过配置文件转换错误提示页
    在web.config文件中的system.web节点添加如下错误处理配置:
    <customErrors mode="On" defaultRedirect="error/error.htm">
    <error statusCode="404" redirect="error/404.htm" />
    </customErrors>
    -》模式共有3个参数
    On表示启用自定义错误跳转
    Off表示禁用自定义错误跳转
    RemoteOnly表示仅远程访问时出错跳转

    案例:在Application_Error中进行页面跳转,记录日志。
    Response.Redirect("~/Error.htm");或者在Web.config中配置。
    Server.GetLastError()获取错误异常。
    将日志记录到log.txt(将该文件放到其他磁盘或者App_Data中)文件中。问题:如果直接写log.txt文件,那么请求人数多的时候会有问题,并发访问问题,如果加lock()又会严重影响性能。解决办法:使用队列。

    Index.aspx

     1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="t4_ErrorHandler.Index" %>
     2 
     3 <!DOCTYPE html>
     4 
     5 <html xmlns="http://www.w3.org/1999/xhtml">
     6 <head runat="server">
     7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     8     <title></title>
     9 </head>
    10 <body>
    11     <form id="form1" runat="server">
    12         <div>
    13 
    14             <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
    15 
    16         </div>
    17     </form>
    18 </body>
    19 </html>

    Index.aspx.cs

     1     public partial class Index : System.Web.UI.Page
     2     {
     3         protected void Page_Load(object sender, EventArgs e)
     4         {
     5 
     6         }
     7 
     8         protected void Button1_Click(object sender, EventArgs e)
     9         {
    10             throw new Exception("小笼包");
    11         }
    12     }

    Global.asax

     1     public class Global : System.Web.HttpApplication
     2     {
     3 
     4         protected void Application_Start(object sender, EventArgs e)
     5         {
     6             //这里的代码只被调用一次,所以只会开启一个写文件的线程
     7             LogHelper.WriteFile();
     8         }
     9 
    10         protected void Session_Start(object sender, EventArgs e)
    11         {
    12 
    13         }
    14 
    15         protected void Application_BeginRequest(object sender, EventArgs e)
    16         {
    17 
    18         }
    19 
    20         protected void Application_AuthenticateRequest(object sender, EventArgs e)
    21         {
    22 
    23         }
    24 
    25         //只要在运行过程中发生错误,就会执行Error事件的处理函数
    26         protected void Application_Error(object sender, EventArgs e)
    27         {
    28             ////记录错误信息
    29             LogHelper.WriteLog();
    30 
    31             //转到友好提示页面
    32             Response.Redirect("/Error/ShowError.html");
    33         }
    34 
    35         protected void Session_End(object sender, EventArgs e)
    36         {
    37 
    38         }
    39 
    40         protected void Application_End(object sender, EventArgs e)
    41         {
    42 
    43         }
    44     }

    ShowError.html

     1 <!DOCTYPE html>
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     5     <title></title>
     6 </head>
     7 <body>
     8     <h1>出错了</h1>
     9 </body>
    10 </html>

    LogHelper.cs

     1     public class LogHelper
     2     {
     3         private static Queue<string> errorQueue;
     4 
     5         static LogHelper()
     6         {
     7             errorQueue = new Queue<string>();
     8         }
     9 
    10         public static void WriteFile()
    11         {
    12             //将一个方法交给线程执行:使用lambda构造委托对象
    13             Thread thread = new Thread(() =>
    14               {
    15                   while (true)
    16                   {
    17                       if (errorQueue.Count > 0)
    18                       {
    19 
    20                           string errorString = errorQueue.Dequeue();
    21 
    22                           string logFilePath = errorString.Split('$')[0];
    23                           string errorString2 = errorString.Split('$')[1];
    24 
    25                           File.AppendAllText(logFilePath, errorString2);
    26                       }
    27                       else
    28                       {
    29                           Thread.Sleep(5000);
    30                       }
    31                   }
    32               });
    33             thread.IsBackground = true;
    34             thread.Start();
    35 
    36         }
    37 
    38         public static void WriteLog()
    39         {
    40             string errorStack = HttpContext.Current.Error.InnerException.StackTrace + "
    ------------
    ";
    41 
    42             string fileName = DateTime.Now.ToString("yyyy-MM-dd");
    43 
    44             string logFilePath = HttpContext.Current.Request.MapPath("/app_code/" + fileName + ".txt");
    45 
    46             //每个浏览器请求过来,都会开启一个新线程执行管道事件
    47             //防止多线程写文件时的错误,而进行一个加锁操作
    48 
    49             //这里虽然使用了内存中的对象,但是并没有解决多线程问题,所以要继续加锁
    50             lock ("dlb")
    51             {
    52                 errorQueue.Enqueue(logFilePath + "$" + errorStack);
    53             }
    54         }
    55     }
  • 相关阅读:
    "rm f xxx"不起作用? 还是需要确认删除?
    (转)C# 3.0语言的新特性——Lambda表达式
    (转)依赖注入的思想(目前见过最好的对DI的描述)
    #import、#include、#import<>和#import””的区别
    Cocoa设计模式之委托
    详解MAC硬盘中各个文件夹
    Cocoa设计模式之单例
    ObjecticeC之关联对象
    UDID被禁用后的集中替代品
    Cocoa设计模式之KVO
  • 原文地址:https://www.cnblogs.com/ninghongkun/p/6368162.html
Copyright © 2011-2022 走看看