在用ASP.NET WebForm开发一个网站时,需要自定义404错误页面. 做法是这样的

在网站根目录下建立了一个404.html的错误页面,然后在Global.asax文件中,加入如下代码:

<%@ Application Language="C#" %>

<script runat="server">

    void Application_Error(object sender, EventArgs e)
{
Response.StatusCode = ;
Server.Transfer("/404.html");
Server.ClearError();
}
</script>

然后运行网站,比如随便输入一个111.aspx时,发现在chrome上会自动redirect到这个404.html, 但是在IE上时,却不会。

在网上查找原因,找到如下答案:

果然,在这个页面中加入一些内容后,这个问题就解决了

另外,这种设置404错误页面,还有一个问题就是,当你在网址中输入不存在的比如111.aspx时,它会自动转入自定义的404.html

但是当你在网址中输入不存在的111, 没有后缀名aspx时,它就不会显示自定义的404.html了

为什么会出现这种情况呢 ? 应该怎么解决呢 ?

解决方法:  你需要在web.config中进行配置,在 <system.webServer>配置节点中加入如下语句

 <httpErrors errorMode="Custom" existingResponse="Replace">
<clear />
<error statusCode="" path="404.html" />
</httpErrors>

详细的处理ASP.NET网站自定义错误页面方法,可以参考如下这篇文章,写的很好

转载自 http://edi.wang/post/2014/1/11/iis7-aspnet-custom-error-best-practice

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

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

本文的范围和限制

  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 == ) || statusCode != )
{
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事件中记录

ASP.NET网站中设置404自定义错误页面的更多相关文章

  1. 新西兰程序员 ASP.NET网站中设置404自定义错误页面

    新西兰程序员 ASP.NET网站中设置404自定义错误页面 在用ASP.NET WebForm开发一个网站时,需要自定义404错误页面. 做法是这样的 在网站根目录下建立了一个404.html的错误页 ...

  2. 在Tomcat中配置404自定义错误页面详解

    这篇文章主要介绍了在Tomcat中配置404自定义错误页面全解,需要的朋友可以参考下 一直使用tomcat,今天想到一个问题,自定义404错误页面, 为了获得很好的用户感受,是不应当向用户暴露404这 ...

  3. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  4. .net自定义错误页面实现升级篇

    问题描述: 在上一篇博文 ".net自定义错误页面实现" 中已经介绍了在.net中如何实现自定义错误页面实现(有需要者可以去上一篇博文了解),单纯按照上一篇博文那样设置,能够实现所 ...

  5. ASP.NET Core中显示自定义错误页面

    在 ASP.NET Core 中,默认情况下当发生500或404错误时,只返回http状态码,不返回任何内容,页面一片空白. 如果在 Startup.cs 的 Configure() 中加上 app. ...

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

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

  7. ASP.NET MVC 中如何用自定义 Handler 来处理来自 AJAX 请求的 HttpRequestValidationException 错误

    今天我们的项目遇到问题 为了避免跨站点脚本攻击, 默认我们项目是启用了 validateRequest,这也是 ASP.NET 的默认验证规则.项目发布后,如果 customError 启用了,则会显 ...

  8. asp.net mvc输出自定义404等错误页面,非302跳转。

    朋友问到一个问题,如何输出自定义错误页面,不使用302跳转.当前页面地址不能改变. 还要执行一些代码等,生成一些错误信息,方便用户提交反馈. 500错误,mvc框架已经有现成解决方法: filters ...

  9. asp.net mvc输出自定义404等错误页面,非302跳转

      朋友问到一个问题,如何输出自定义错误页面,不使用302跳转.当前页面地址不能改变. 还要执行一些代码等,生成一些错误信息,方便用户提交反馈. 500错误,mvc框架已经有现成解决方法: filte ...

随机推荐

  1. zoj 3785 What day is that day? (打表找规律)

    题目 思路:比赛的时候有想过找循环节,但是,打表打错了. 后来,看着过了挺多人,就急了, 看了一下别人的时间 耗时都挺长的,就以为不是找规律, 没想到真是找规律,不过,这个题的数据可能挺大的. AC代 ...

  2. super.getClass()方法

    下面程序的输出结果是多少? importjava.util.Date; public class Test extends Date{ public static void main(String[] ...

  3. 使用ffmpeg向crtmpserver发布rtsp流

    ffmpeg的调用命令如下: ffmpeg -re -i xxx.mp4  -vcodec copy -acodec copy -f rtsp rtsp://127.0.0.1/live/mystre ...

  4. svn强制提交备注信息

    当我们用tortoisesvn,提交代码时,有很多人不喜欢写注释的,代码版本多了,根本搞不清,哪个版本改了什么东西?所以如果加一些注释的话,我们看起来,也方便很多.所以在提交的时候,我会强制要求,写注 ...

  5. SPFile的使用

    转:http://blog.csdn.net/pclzr/article/details/7591741 SPFile对应于SharePoint对象模型中的文件,它的使用方法与SPFolder类大致相 ...

  6. html input readonly 和 disable的区别

    Readonly和Disabled它们都能够做到使用户不能够更改表单域中的内容.但是它们之间有着微小的差别,总结如下: Readonly只针对input(text / password)和textar ...

  7. asp.net MVC 应用程序的生命周期(下)

    看看上面的UrlRoutingModule源码里面是怎么实现Init方法的,Init()方法里面我标注红色的地方: application.PostResolveRequestCache += new ...

  8. Jedis的Sharded源代码分析

    概述 Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表.当业务的数据量非常庞大时,需要考虑将数据存储到多个缓存节点上,如何定位数据应该存储的节点, ...

  9. CCMoveTo 等函数理解

    CCMoveTo: 使用CCMoveTo action来让对象从右侧屏幕外移动到屏幕左侧.注意可以通过指定duration参数控制这一过程需要多久,这里我们随机给他2-4秒的时间. CCCallFun ...

  10. sizeof和strlen小结

    sizeof和strlen小结 写在前面 之所以要总结一下sizeof和strlen的用法和区别,是因为这些知识可以帮助我们更加深入的理解各种数据结构在内存中的占用情况,也许表面上看好像没有多大用处, ...