一直知道有.NET有相关的配置,但没有实际作过,觉得改下设定就能够,结果实际使用的时候仍是遇到很多问题,因此要记录一下。安全
刚开始不想改程序代码,因此直接就想到了IIS里面的错误页配置配置,一开始反复测试,设置改了不少,可是没有效果,后来发现是静态页的配置,尚未进入MVC的程序部分,因此对于.NET MVC这种动态页是不生效的,应该使用.NET错误页选项服务器
静态页配置流程以下:mvc
如上图所示,IIS中配置对错误的响应有三种方式,默认状况是第三个,本地访问显示详细错误信息,外部地址访问显示自定义页面,这样方便开发者调试,若是没有设置专门的错误页会使用IIS自带的样式,也就是第二张图中的配置,根据路径咱们能够找到这样一个文件夹,里面都是错误提示的静态页,对应不一样的状态代码app
咱们能够把IIS设置为均使用自定义错误页看下效果,或者直接经过文件访问测试
上面那张是详细的静态404错误,能够看到会暴露咱们系统路径,下面则是默认的自定义错误页网站
静态错误的默认页有相应的设置,看似能够修改,有“文件”、“执行URL”、“重定向”三种,可是实际设置一下就会发现报错:锁定错误.net
经过这个错误咱们去搜索解决方法能够看到一些人说将web.config中的httperror节下的defaultPath解锁便可,但彷佛这是IIS7之前的设置,在IIS10中并无相应的选项,看到一些说明提到多是官方使用了更加安全的管理机制,由于发现这边的配置是静态页相关,不符合个人须要,没有深刻研究,若是必定要使用这种能够看看这篇博客,试试可否经过系统命令解决锁定的问题3d
.NET错误页的设置与静态页差很少,除了入口不同,配置的选项也不太相同,可是总体意思同样
能够看到这里要求是绝对URL,因此实际使用起来应该是不太方便,因此没有找到太多相关资料。另外,须要web.conig中的customError设为On,部分异常如500会自动跳转到MVC的默认错误页Home/Error
使用IIS的错误页处理虽然不用改代码,可是维护起来局限性不少,最终仍是应该经过程序进行全局异常捕获
经过程序控制的方法我想到两种,一个是使用全局配置文件Global.asax中的Application_Error方法,另外一个是使用MVC的过滤器,默认的四种过滤器中就包含异常过滤
这种方法对于WebForm和MVC都是通用的,在ASP.NET中,只要网站程序抛出未捕获的异常都会触发Application_Error事件。
使用此方法必定要把GlobalFilter全局过滤器中的HandleErrorAttribute注册取消掉,也能够将配置文件中的customErrors节点关闭,不然HTTP 500的错误将不会被Application_Error事件捕获。
捕获到异常以后咱们能够很容易地跳转到静态页面
protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); var httpStatusCode = (exception as HttpException)?.GetHttpCode() ?? 700; //若是为空则走自定义 var httpContext = ((MvcApplication)sender).Context; httpContext.ClearError(); switch (httpStatusCode) { case 404: httpContext.Response.Redirect("~/Error/404.htm"); break; default: httpContext.Response.Redirect("~/Error/500.htm"); break; } }
在通常状况下咱们也能够指向一个控制器
protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); var httpStatusCode = (exception as HttpException)?.GetHttpCode() ?? 700; //若是为空则走自定义 var httpContext = ((MvcApplication)sender).Context; httpContext.ClearError(); var routeDic = new RouteValueDictionary { {"controller", "Home"}, { "action","Error"} }; httpContext.Response.RedirectToRoute("Default", routeDic); }
可是在实际的业务中遇到了一些http请求的问题,在处理一部分代码抛出的异常时会出现“服务器没法在已发送HTTP标头以后······”这一系列异常,如“设置状态”、“追加标头”等,这个时候跳转要使用另外一种写法
protected void Application_Error(object sender, EventArgs e) { Server.ClearError(); Response.TrySkipIisCustomErrors = true; var routeData = new RouteData(); IController controller = new HomeController(); routeData.Values.Add("controller", "Home"); routeData.Values.Add("action", "Error"); controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData)); Response.End(); }
这里要注意的一点是若是要使用Area中的控制器不能写成routeData.Values.Add,而是使用DataTokens
routeData.DataTokens.Add("area", "TestArea");