ASP.NET Core 中文文檔 第三章 原理(5)錯誤處理


原文:Error Handling
作者:Steve Smith
翻譯:謝煬(Kiler)
校對:高嵩(jack2gs)何鎮汐

當你的ASP.NET應用發生錯誤的時候, 你可以采用本文所述的各種方法來處理這些問題。

章節:

查看或者下載示例代碼

配置錯誤處理頁面

你在 Startup 類的 Configure() 方法中為每一個請求配置管道 (更多內容請參考 Application Startup)。 你可以輕松的添加一個僅僅適用於開發階段的簡單異常頁面。只需要在項目中添加 Microsoft.AspNetCore.Diagnostics 依賴,並且添加一行代碼到 Startup.csConfigure() 方法里面:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseIISPlatformHandler();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

以上代碼包含一個檢查,以確保添加調用 UseDeveloperExceptionPage 的環境是開發環境。這是一個好的實踐,因為你通常情況下並不希望在應用程序已經處於生產環境的情況下,將你的應用程序的詳細異常信息對外公開. 詳細了解如何配置環境
示例應用程序包括一個創建異常的簡單機制的例子:

public static void HomePage(IApplicationBuilder app)
{
    app.Run(async (context) =>
    {
        if (context.Request.Query.ContainsKey("throw"))
        {
            throw new Exception("Exception triggered!");
        }
        var builder = new StringBuilder();
        builder.AppendLine("<html><body>Hello World!");
        builder.AppendLine("<ul>");
        builder.AppendLine("<li><a href=\"/?throw=true\">Throw Exception</a></li>");
        builder.AppendLine("<li><a href=\"/missingpage\">Missing Page</a></li>");
        builder.AppendLine("</ul>");
        builder.AppendLine("</body></html>");

        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync(builder.ToString());
    });
}

如果請求中包含一個變量名為 throw 的非空查詢字符串 (例如,路徑: /?throw=true), 那么就會拋出一個異常。如果環境被設置為 Development , 開發者異常頁面將會被顯示:

當不在開發模式下, 建議使用 UseExceptionHandler 方法來配置一個錯誤處理路徑:

app.UseExceptionHandler("/Error");

使用開發者異常頁面

當Web請求中發生無法捕獲異常的時候,開發者異常頁面會顯示有用的調試信息。頁面包含幾個選項卡頁面來顯示Web請求中引發的異常信息。 第一個選項卡頁面包含錯誤堆棧跟蹤信息:

第二個選項卡頁面顯示查詢字符串信息,如果有的話:

在這個案例里面,你可以看到 throw 參數的值被傳遞到了請求。這個請求不包含任何cookies,但是如果有任何cookies,他們的值會顯示在cookies選項卡頁面。你可以在最后一個選項卡頁面查看到頭信息:

配置狀態碼頁面

在默認情況下,你的應用程序無法為Http狀態碼返回(例如:500 (服務器內部錯誤) or 404 (文件無法找到))提供一個富文本的HTTP狀態碼頁面。你可以在 Configure 方法中加入一行 StatusCodePagesMiddleware 代碼:

app.UseStatusCodePages();

在默認情況下,系統會為普通的http狀態碼添加一個非常簡單純文本的處理,例如,下面是404無法找到文件狀態碼返回的結果。

中間件提供不同的擴展方法,你也可以使用自定義lambda表達式來配置參數:

  app.UseStatusCodePages(context =>
  context.HttpContext.Response.SendAsync("Handler, status code: " +
  context.HttpContext.Response.StatusCode, "text/plain"));

另外, 你也可以簡單的傳遞一個內容類型和格式化字符串:

app.UseStatusCodePages("text/plain", "Response, status code: {0}");

中間件也能處理重定向請求 (無論是絕對路徑還是相對路徑), 把狀態碼作為URL的一部分進行傳遞:

app.UseStatusCodePagesWithRedirects("~/errors/{0}");

在上面的案例中, 客戶端瀏覽器遇到 302 / Found狀態碼返回時,會重定向到指定的頁面.
另外,中間件也提供設置一個新的路徑字符串的方式來重新執行請求。

app.UseStatusCodePagesWithReExecute("/errors/{0}");

方法 UseStatusCodePagesWithReExecute 會返回原始的瀏覽器狀態碼頁面,但是也會執行路徑中指定的處理程序。

如果你需要對某些請求禁止狀態碼頁面, 可以使用以下代碼:

var statusCodePagesFeature = context.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
  statusCodePagesFeature.Enabled = false;
}

錯誤處理在CS交互模式下的限制

Web應用在錯誤處理功能上因為斷開HTTP請求和響應的特性有些特別的限制,有的應用程序,在你設計錯誤處理行為時請注意以下幾點。

  1. 一旦響應文件頭發送出去以后,你就無法再修改響應的狀態碼了,無論是任何異常頁面或處理程序都無法執行。響應必須完成或者連接中斷退出。
  2. 如果客戶端在響應中期斷開,你無法把當前響應的剩余內容發送給客戶端。
  3. 在你的錯誤處理層之下,總是有可能存在有例外的一層。
  4. 不要忘了,錯誤處理頁面也會產生異常. 生產環境異常頁面采用純靜態頁面是個不錯的建議。

遵從上述建議將有助於確保您的應用程序保持響應,並且能很好地處理應用程序可能發生的異常。

服務器錯誤處理

除了你的應用程序中的錯誤處理邏輯,托管應用程序的服務器也將執行一些錯誤處理。如果服務器在頭信息發送出去之前捕獲到異常,它會發出不帶主體的500內部服務器錯誤響應。如果在頭文件發送出去之后捕獲到異常必須關閉連接。那些不是被你的應用程序處理的請求將被服務器處理,並且發生的任何異常將被服務器的錯誤處理機制來處理。任何在你的應用程序里面配置好自定義錯誤頁、錯誤處理中間件、過濾器都無法影響此行為。

Startup 錯誤處理

處理異常最為棘手的地方是在你的應用程序啟動的時候。只有承載層可以處理應用程序的啟動過程中發生的異常。應用程序啟動時發生的異常也會影響服務器的行為。例如,要啟用SSL in Kestrel,有些必須用 KestrelServerOptions.UseHttps() 配置服務器。如果一個異常在 Startup 代碼行之前發生,則默認情況下托管將捕獲異常,並啟動服務器,然后在非SSL端口上顯示一個錯誤頁面。如果有異常情況發生在該行執行之后, 則錯誤頁面將通過HTTPS服務生效。

ASP.NET MVC 錯誤處理

異常過濾器

異常過濾器可以在 MVC 應用程序的全局范圍內或者每個Controller或者每個Action上進行配置。這些過濾器會處理controller action或其他過濾器的執行過程中發生的任何未處理的異常,其他情況則不會被調用。異常過濾器更多內容請見 過濾器

小技巧
異常過濾器捕獲MVC Action中發生的異常是很好的,但他們不如錯誤處理中間件靈活。一般情況下盡可能使用中間件,只有當在你需要在處理異常的時候需要特別指定某些MVC action的時候,過濾器才被建議使用。

處理模型狀態錯誤

模型驗證 在每個controller action被調用之前發生,Action方法的職責是檢查 ModelState.IsValid 並作出適當的交互反應。在大部分情況下,特定的交互會返回特定的錯誤響應,最好詳細說明模型驗證失敗的原因。

有些應用程序會選擇遵循標准慣例處理模型驗證錯誤,在這種情況下,過濾器可以作為某些策略的實現場所。您應該測試你的Action是否與有效和無效的模型狀態有關聯(了解更多有關 測試controller邏輯)的行為。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM