一直知道有.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");