首页 > 其他 > 详细

028-全局错误处理

时间:2017-02-05 18:04:18      阅读:126      评论:0      收藏:0      [点我收藏+]

全局文件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 + "\r\n------------\r\n";
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     }

 

028-全局错误处理

原文:http://www.cnblogs.com/ninghongkun/p/6368162.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!