针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结


汪宇杰
2014-1-11 星期六 02:31

455 Reads 1 Comments

自定义错误页面和异常记录是个很古老的话题了,但依旧可以让人爆到现在。在我做了无数次试验并总结经验和原则后,写下本文,已警后人。

本文的范围和限制

  1. 本文仅仅适用于部署在IIS7或以上版本中的ASP.NET 4.0集成模式应用程序。IIS7以上的意思是Windows Server 2008以上服务器适用。我已在WS2012R2,IIS8上测过。
  2. 本文的方法均适用于ASP.NET WebForm和MVC应用程序。

本文针对的问题

  1. 静态错误页面好还是动态错误页面好?我该如何设计ASP.NET网站错误处理?
  2. 我不希望错误页面后面跟上aspxerrorpath=…这个小尾巴。
  3. 我的自定义错误页面在VS里调试是好的,为什么部署到服务器上就出不来了?
  4. 我的自定义错误页面可以正常显示,但为什么返回的Http状态码不正确?
  5. 异常日志该怎样记录,有没有比较好的实践?

一、错误页面的选择

选择静态html页面作为错误页,还是使用.aspx或是MVC View来显示错误页面好?这个问题许多人的偏好都不一样。我强烈建议大家用html静态页面作为错误页。请看分析:

首先,用动态页面的人,无非是为了解决三个问题:显示错误摘要、记录日志、返回正确的状态码。但是,动态页面最大的问题在于,它们本身是要经过ASP.NET和后台代码处理的,万一你的后台代码是爆的,或者ASP.NET自己爆了,那你的错误页面一旦被请求,本身就会引发另一个错误。而静态html是不会有这个问题的。至于在MVC里专门建一个ErrorController的做法就更不可取了。MVC是基于ASP.NET之上的,MVC的Controller只能抓MVC自己的错误,抓不到ASP.NET的错误,意思就是说,当你的错误并不在MVC层面上的时候,ErrorController没有任何用武之地。例如,当你部署的MVC应用程序缺少MVC的dll时候,MVC框架本身都跑不起来,这个错误如何去抓?

另外,我认为在一个Internet站点上,绝不应该向访客显示任何的错误摘要。这是非常不安全的。所以完全没有必要用动态页面。

至于返回正确状态码的问题是这样的:不少小伙伴发现自己的错误页面能够显示,但返回的状态码是200OK,所以无奈之下用动态页面,写上Response.StatusCode = 500这样的代码来强撸。这个在稍后的文章里有解决方案,所以不要为了状态码而冒险用动态页面。有的小伙伴会问,我只写一笔Response.StatusCode=500能有什么风险?呵呵,想想这种情况:404.cshtml,razor引擎的dll不见了……

另外,一个原则是:错误页面应当是独立的。如果你的静态页面要用到图片和CSS等外部资源,建议嵌入在页面里边,做成单文件的,以免显示错误页面时请求相关资源再次引发异常。小伙伴又要问了,请求个CSS和图片什么的,肿么会引发异常呢?那你看看这个:resources.axd?image=…,呵呵。

那么用了静态页面以后,记录日志怎么办呢?正确的方法应该是交给Global.asax中的“Application_Error”事件处理。稍后会有翔解。

二、配置错误页面:customErrors VS httpErrors

首先,错误页面的显示方式有两种。如果你打开IIS,会看到两个配错误页的地方:.NET Error Pages和Error Pages。

站在开发者的角度来说,ASP.NET Section下的“.NET Error Pages”就是web.confg/system.web/customErrors节点。而IIS Section下的”Error Pages”是web.config/system.webServer/httpErrors节点,这个是IIS7以上特有的。

任何在IIS上对这两处的更改其实都是在修改web.config文件。

那么我们该用哪一个来配置自定义错误页呢?我的一个原则是:让IIS向用户展示错误页面,而不要依赖于ASP.NET。 猿因如下:

CustomError的问题:

a)  在默认情况下,CustomError会采用302重定向的方式来展示错误页面,如果客户端请求了一个404的页面,那它得到的将会是一个302紧接着一个200OK,对于人类来说这是OK的,毕竟用户看到了友好的错误页面,但搜索引擎会认为这个不存在的地址是正常的页面,并把你的404页面收入搜索结果。并且每次引发错误,URL后边都会跟上aspxerrorpath这个小尾巴,比如:

http://yoursite.com/404.html?aspxerrorpath=/somethingnotexsit

b) 在配置了redirectMode=“ResponseRewrite”后,会引发一个问题,09年就有人当bug提交到MS Connect上了,但目前微软不打算fix这个bug。即该模式在VS自带的ASP.NET Development Server上是有效的,浏览器显示的是解析后的HTML页面,而部署到IIS上之后,浏览器显示是raw html,即你的错误页面的HTML代码。并且该行为不具有确定性,天晓得你的网站换个环境部署又会爆成什么样。

c)  IIS7以上版本的特殊性:在集成模式下,IIS的错误页面会优先于ASP.NET错误页面,即IIS的默认错误页会覆盖你配置的CustomErrors页面,这就是为什么你在VS下调试是好的,部署到服务器上就爆了。

在IIS7之后,取决于你的配置,用户的请求并不都一定在ASP.NET管线上处理。如果引发异常的地方不在ASP.NET,那就不会显示CustomErrors的错误页面。

所以,我强烈建议大家用httpErrors节点替代CustomErrors来配置错误页面。

三、File还是ExecuteURL:httpErrors的正确配法

先贴一个正确的配置样例:是用File配的。

注意两处地方:

  1. 斜杠是Windows文件路径的反斜杠“\”而不是网址URL的斜杠“/”
  2. Path不要以“~”或“\”开头

不要问我为什么,我也不知道,反正这么弄就是好的。

如果你不幸用了ExecuteURL,你会发现URL路径只能以“/”开头:

并且你的错误页会返回200OK而不是正确的404、500等错误码。这在我以前的文章里写过:

http://diaosbook.com/Post/2012/6/24/correct-way-to-implement-custom-error-page-return-statecode-instead-of-http-200

而用File的意思是,当错误被爆出来之后,IIS会把目标File,比如404.html的内容,塞到当前的Response流里面,保持Http状态码依旧是404。这就是我们想要的。

四、异常日志记录

文章在一开始就提了个问题,木有了动态页面,怎么记录错误日志?我的做法是在Global.asax里处理。

Application_Error事件样例代码如下:

var exception = HttpContext.Current.Server.GetLastError(); if (null != exception) { // by default 500 var statusCode = (int)HttpStatusCode.InternalServerError; if (exception is HttpException) { statusCode = new HttpException(null, exception).GetHttpCode(); } else if (exception is UnauthorizedAccessException) { // to prevent login prompt in IIS // which will appear when returning 401. statusCode = (int)HttpStatusCode.Forbidden; } if ((LogHttpNotFound && statusCode == 404) || statusCode != 404) { if (null != _loggerFunc) { LoggerFunc(string.Format("ASP.NET Error Captured, Request URL: {0}, Exception:", HttpContext.Current.Request.Url), exception); } } ExceptionInfo = exception.Message; _statusCode = statusCode; }

一个小小的建议是不要记录404错误,因为你的网站在Internet上会被各种搜索引擎、扫描工具和黑客菊爆,有一种攻击手段是通过字典猜解目录,返回404就是不存在,返回403就是存在。所以,当你碰到这种无聊黑客的时候,如果记录了404请求,那你的日志会非常的大……

我记日志用的组件是NLog,配置简单,使用容易。Log4net这货已经好久没更新了。

如果你决定自己设计日志模块,那要记住两个原则:

日志模块本身并不能因为自己爆掉而影响整个系统运行,即任何在日志模块里的异常不应该向外冒泡。

考虑并发写日志的情况,日志操作应该是Fire and Forget的,不能让应用程序等待日志写入。

五、总结

  1. 采用静态html页面作为错误页。
  2. 采用httpErrors配置错误页面,目的是兼容IIS7以上环境、返回正确错误码、去掉aspxerrorpath小尾巴。
  3. 日志记录写在Global.asax里,在Application_Error事件中记录。

转载于:https://www.cnblogs.com/sherlock99/p/4109035.html

[转载]针对IIS7以上的ASP.NET网站自定义错误页面与异常日志总结相关推荐

  1. Win7 IIS7.5运行ASP时出现500错误的解决办法

    http 500内部服务器错误说明IIS服务器无法解析ASP代码,下面为大家介绍下Win7 IIS7.5运行ASP时出现500错误的解决办法 http 500内部服务器错误说明IIS服务器无法解析AS ...

  2. ASP.NET自定义错误页面(转)

    ASP.NET自定义错误页面(转) ASP.NET 提供三种用于在出现错误时捕获和响应错误的主要方法:Page_Error 事件.Application_Error 事件以及应用程序配置文件 (Web ...

  3. 解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题

    我们基于 Razor Class Library 实现了自定义错误页面的公用类库(详见之前的随笔),但是在实际使用时发现如果在 middleware 中发生了异常,则不能显示自定义错误页面,而是返回默 ...

  4. ASP.NET Core中显示自定义错误页面-增强版

    之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...

  5. ASP.NET自定义错误页面,分离配置信息,多环境发布

    今天主要说三个内容,都是和ASP.NET有关的内容. 第一个关于自定义错误的,就是在网站出现404或者500的错误,如何给用户显示一个友好的界面. 第二个是分离配置文件web.config,如果配置信 ...

  6. 【转】ASP.net MVC自定义错误处理页面的方法

    在ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAttribute特性,那 ...

  7. ASP.net MVC自定义错误处理页面的方法

    在ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAttribute特性,那 ...

  8. 【前端】20款国外非常漂亮的优秀网站404错误页面HTML模板

    404错误页面是一个非常普遍的现象,该页面的目的是告诉浏览者其所请求的页面不存在或链接错误,同时引导用户使用网站其他页面而不是关闭窗口离开.虽然404错误页面在所难免,但网页设计师们却可以在该页面上做 ...

  9. ASP.NET自定义错误页面

    ASP.NET 提供三种用于在出现错误时捕获和响应错误的主要方法:Page_Error 事件.Application_Error 事件以及应用程序配置文件 (Web.config). 如果您不调用 S ...

最新文章

  1. usaco Money system
  2. java 给窗口加菜单_程序求助:如何给窗口添加菜单?
  3. 查处的数据如何乱序_老司机总结常用镜像方法,让镜像数据更加可靠
  4. Paxos 实现日志复制同步(Multi-Paxos)
  5. python 多进程multiprocessing 队列queue报错:AttributeError: Can't pickle local object
  6. ubuntu下hbase的伪分布式安装与配置
  7. CSDN下载频道2014年11月4日本-5日常维护公告
  8. 【Bash】实现指定目录下的文件编码转换,以原文件名保存
  9. 在线代码编辑器 CodeMirror 配置说明 - javascript开发的代码语法高亮显示引擎
  10. 2010——满地遍是网页防篡改和WAF
  11. mysql编译安装后各种常见错误集锦
  12. 【Android自定义View】仿Photoshop取色器ColorPicker(二)
  13. 如何免费获取基于公网 IP 的 SSL 证书 (无需域名)
  14. Python爬虫实战之爬取饿了么信息
  15. 10006---当当架构部张亮:从码农到大牛,技术与心境的双重提升
  16. 中山c 语言培训中心,中山英语口语培训中心
  17. 睿联技术在创业板过会:收入依赖摄像机单机,计划募资11亿元
  18. 本科毕业论文参考文献可以随便写吗?
  19. 《CSAPP》(第3版)答案(第三章)(一)
  20. S3C2440 开发板实战(9):poll机制

热门文章

  1. postgre非零相除等于0_LeetCode刷题实战29:两数相除
  2. 中南大学 科学计算与MATLAB语言 11矩阵求值
  3. 一级计算机考试中的DBF,2017年计算机等考一级WPS2000辅导:使用DBF格式内容的方法...
  4. mybatis-plus对datetime返回去掉.0_0欧姆电阻到底有没有用?这12个作用说明其不可或缺...
  5. 前端开发中如何将文件夹中的图片变为背景图_如何用Elementor设计banner
  6. java标签不显示文字_此程序在运行后,窗体上不显示标签的文字,也不显示图标,我自己检查也没发现什么问题,请大神帮帮忙看看我哪个地方有问题?...
  7. clickhouse修改表的TTL
  8. spark数据倾斜解决之提高并行度
  9. Java Web学习总结(15)——JSP指令
  10. (三)java版spring cloud+spring boot 社交电子商务平台 - Spring Cloud集成项目简介