《ASP.NET Core 6框架揭秘》實例演示[32]:錯誤頁面的N種呈現方式

由于ASP.NET是一個同時處理多個請求的Web應用框架,所以在處理某個請求過程中出現異常并不會導致整個應用的中止。出于安全方面的考量,為了避免敏感信息外泄,客戶端在默認情況下并不會得到詳細的出錯信息,這無疑會在開發過程中增加查錯和糾錯的難度。對于生產環境來說,我們也希望最終用戶能夠根據具體的錯誤類型得到具有針對性并且友好的錯誤消息。ASP.NET提供的相應的中間件可以幫助我們將定制化的錯誤信息呈現出來。[本文節選《ASP.NET Core 6框架揭秘》第21章]

目錄
[2101]開發者異常頁面的呈現(源代碼)
[2102]定制異常頁面的呈現(源代碼)
[2103]利用注冊的中間件處理異常(源代碼)
[2104]針對異常頁面的重定向(源代碼)
[2105]基于響應狀態碼錯誤頁面的呈現(設置響應內容模板)(源代碼)
[2106]基于響應狀態碼錯誤頁面的呈現(提供異常處理器)(源代碼)
[2107]基于響應狀態碼錯誤頁面的呈現(利用中間件創建異常處理器)(源代碼)

[2101]開發者異常頁面的呈現

如果ASP.NET應用在處理某個請求時出現異常,它一般會返回一個狀態碼為“500 Internal Server Error”的響應。為了避免一些敏感信息的外泄,客戶端只會得到一個很泛化的錯誤消息。以如下所示的程序為例,處理根路徑的請求時都會拋出一個InvalidOperationException類型的異常。

var?app?=?WebApplication.Create();
app.MapGet("/",
void?()?=>?throw?new?InvalidOperationException("Manually?thrown?exception"));
app.Run();

利用瀏覽器訪問這個應用總是會得到圖1所示的錯誤頁面。可以看出這個頁面僅僅告訴我們目標應用當前無法正常處理本次請求,除了提供的響應狀態碼(“HTTP ERROR 500”),它并沒有提供任何有益于糾錯的輔助信息。

6cddf0faa8a6ba85caa4f9d8b4bff1c3.png

圖1 默認的錯誤頁面

有人認為瀏覽器上雖然沒有顯示任何詳細的錯誤信息,但這并不意味著HTTP響應報文中也沒有攜帶任何詳細的出錯信息。如下所示的服務端會返回的HTTP響應報文,該響應沒有主體內容,有限的幾個報頭也并沒有承載任何與錯誤有關的信息。

HTTP/1.1?500?Internal?Server?Error
Content-Length:?0
Date:?Sun,?07?Nov?2021?08:34:18?GMT
Server:?Kestrel

由于應用并沒有中斷,瀏覽器上也并沒有顯示任何具有針對性的錯誤信息,我們無法知道背后究竟出現了什么錯誤。這個問題有兩種解決方案:一種是利用日志,ASP.NET在處理請求過程中出現異常時,會發出相應的日志事件,我們可以注冊相應的ILoggerProvider對象將日志輸出到指定的渠道。另一種解決方案就是利用注冊的DeveloperExceptionPageMiddleware中間件顯示一個“開發者異常頁面(Developer Exception Page)”。

如下的演示程序調用IApplicationBuilder接口的UseDeveloperExceptionPage擴展方法來注冊了這個中間件。該程序注冊了一個路由模板為“{foo}/{bar}”的終結點,后者在處理請求時直接拋出異常。

var?app?=?WebApplication.Create();
app.UseDeveloperExceptionPage();
app.MapGet("{foo}/{bar}",
void?()?=>?throw?new?InvalidOperationException("Manually?thrown?exception"));
app.Run();

一旦注冊了DeveloperExceptionPageMiddleware中間件,ASP.NET應用在處理請求過程中出現的異常信息就會以圖2所示的形式直接出現在瀏覽器上,我們可以在這個頁面中看到幾乎所有的錯誤信息,包括異常的類型、消息和堆棧信息等。

657d834620c5c1a0e3d2ea21c856b116.png

圖2 開發者異常頁面(基本信息)

開發者異常頁面除了顯示與拋出的異常相關的信息,還會以圖3所示的形式顯示與當前請求上下文相關的信息,包括當前請求URL攜帶的所有查詢字符串、所有請求報頭、Cookie的內容和路由信息(終結點和路由參數)。如此詳盡的信息無疑會極大地幫助開發人員盡快找出錯誤的根源。由于此頁面上往往會攜帶一些敏感的信息,所以只有在開發環境才能注冊這個中間件。實際上Minimal API在開發環境會默認注冊這個中間件。

341817f0802a7e2a097816697bb1a735.png

圖3 開發者異常頁面(詳細信息)

[2102]定制異常頁面的呈現

由于ExceptionHandlerMiddleware中間件直接利用提供的RequestDelegate委托來處理出現異常的請求,我們可以利用它呈現一個定制化的錯誤頁面。如下的演示程序通過調用IApplicationBuilder接口的UseExceptionHandler擴展方法注冊了這個中間件,提供的的ExceptionHandlerOptions配置選項指定了一個指向HandleErrorAsync方法的RequestDelegate委托作為異常處理器。

var?options?=?new?ExceptionHandlerOptions?{?ExceptionHandler?=?HandleErrorAsync?};
var?app?=?WebApplication.Create();
app.UseExceptionHandler(options);
app.MapGet("/",
void?()?
=>?throw?new?InvalidOperationException("Manually?thrown?exception"));
app.Run();static?Task?HandleErrorAsync(HttpContext?context)?
=>?context.Response.WriteAsync("Unhandled?exception?occurred!");

如上面的代碼片段所示,HandleErrorAsync方法僅僅是將一個簡單的錯誤消息(Unhandled exception occurred!)作為響應的內容。演示程序注冊了一個針對根路徑(“/”)的并且直接拋出異常的終結點,當我們利用瀏覽器訪問該終結點時,這個定制的錯誤消息會以圖4所示的形式直接呈現在瀏覽器上。

ece2abfd45ef6b316553531fc11c8a56.png

圖4 定制的錯誤頁面

[2103]利用注冊的中間件處理異常

由于ExceptionHandlerMiddleware中間件的異常處理器的是一個RequestDelegate委托,而IApplicationBuilder對象具有利用注冊的中間件來創建這個委托對象的能力,所以用于注冊該中間件的UseExceptionHandler擴展方法提供了一個參數類型為Action<IApplicationBuilder>重載。如下的演示程序調用了這個方法,在提供的作為參數的Action<IApplicationBuilder>委托中,我們調用了IApplicationBuilder接口的Run方法注冊了一個中間件來處理異常,訪問啟動后的程序同樣會得到如圖21-4的錯誤信息(S2103)。

var?app?=?WebApplication.Create();
app.UseExceptionHandler(app2?=>?app2.Run(HandleErrorAsync))
app.MapGet("/",
void?()?
=>?throw?new?InvalidOperationException("Manually?thrown?exception"));
app.Run();static?Task?HandleErrorAsync(HttpContext?context)??
=>?context.Response.WriteAsync("Unhandled?exception?occurred!");

[2104]針對異常頁面的重定向

如果應用已經提供了一個錯誤頁面,ExceptionHandlerMiddleware中間件在進行異常處理時可以直接重定向到該頁面就可以了。如下的演示程序采用這種方式調用了另一個UseExceptionHandler擴展方法重載,作為參數的字符串(“/error”)指定的就是錯誤頁面的路徑,訪問啟動后的程序同樣會得到如圖4的錯誤信息。

var?app?=?WebApplication.Create();
app.UseExceptionHandler("/error");
app.MapGet("/",
void?()?
=>?throw?new?InvalidOperationException("Manually?thrown?exception"));
app.MapGet("/error",?HandleErrorAsync);
app.Run();static?Task?HandleErrorAsync(HttpContext?context)??
=>?context.Response.WriteAsync("Unhandled?exception?occurred!");

[2105]基于響應狀態碼錯誤頁面的呈現(設置響應內容模板)

我們知道HTTP語義中的錯誤是由響應的狀態碼來表達的,涉及的錯誤大體劃分為如下兩種類型:

  • 客戶端錯誤:表示因客戶端提供不正確的請求信息而導致服務器不能正常處理請求,響應狀態碼的范圍為400~499。

  • 服務端錯誤:表示服務器在處理請求過程中因自身的問題而發生錯誤,響應狀態碼的范圍為500~599。

StatusCodePagesMiddleware中間件幫助我們針對響應狀態碼對錯誤頁面進行定制。該中間件只有在后續管道產生一個錯誤響應狀態碼(范圍為400~599)才會將錯誤頁面呈現出來。如下的演示程序通過調用UseStatusCodePages擴展方法注冊了這個中間件,作為參數的兩個字符串分別是響應的媒體類型和作為主體內容的模板,占位符“{0}”將被狀態碼進行填充。

var?app?=?WebApplication.Create();
app.UseStatusCodePages("text/plain",?"Error?occurred?({0})");
app.MapGet("/",?void?(HttpResponse?response)?=>?response.StatusCode?=?500);
app.Run();

我們針對根路徑(“/”)注冊了一個終結點,后者在處理請求時直接返回狀態碼為500的響應。應用啟動后,針對該路徑請求將會得到如圖5所示的錯誤頁面。

2306d634e74177f4dfe4f60aeb896efe.png

圖5 針對錯誤響應狀態碼定制的錯誤頁面

[2106]基于響應狀態碼錯誤頁面的呈現(提供異常處理器)

StatusCodePagesMiddleware中間件的錯誤處理器體現為一個Func<StatusCodeContext, Task>委托,作為輸入的StatusCodeContext是對當前HttpContext上下文的封裝。如下的演示程序定義了一個與此委托具有一致聲明的HandleErrorAsync來呈現錯誤頁面,UseStatusCodePages擴展方法指定的Func<StatusCodeContext, Task>委托指向這個方法。

using?Microsoft.AspNetCore.Diagnostics;
var?random?=?new?Random();
var?app?=?WebApplication.Create();
app.UseStatusCodePages(HandleErrorAsync);
app.MapGet("/",?void?(HttpResponse?response)?
=>?response.StatusCode?=?random.Next(400,599));
app.Run();static??Task?HandleErrorAsync(StatusCodeContext?context)
{var?response?=?context.HttpContext.Response;return?response.StatusCode?<?500??response.WriteAsync($"Client?error?({response.StatusCode})"):?response.WriteAsync($"Server?error?({response.StatusCode})");
}

我們針對根路徑(“/”)注冊的終結點會隨機返回一個狀態碼在(400,599)區間內的響應。用來處理錯誤的HandleErrorAsync方法會根據狀態碼所在的區間(400~499, 500~599)分別顯式“Client error”和“Server error”。應用啟動后,針對根路徑的請求會得到如圖6所示錯誤頁面。

53fdbf630d36778c5055733299e78ec6.png

圖6 針對錯誤響應狀態碼定制的錯誤頁面

[2107]基于響應狀態碼錯誤頁面的呈現(利用中間件創建異常處理器)

在ASP.NET的世界里,針對請求的處理總是體現為一個RequestDelegate委托,而IApplicationBuilder對象具有根據注冊的中間件構建這個委托的能力,所以 UseStatusCodePages方法還具有另一個將Action<IApplicationBuilder>委托作為參數的重載。如下的演示程序調用了這個重載,我們利用提供的委托調用了IApplicationBuilder對象的Run擴展方法注冊了一個中間件來處理異常(S2107)。

var?random?=?new?Random();
var?app?=?WebApplication.Create();
app.UseStatusCodePages(app2?=>?app2.Run(HandleErrorAsync));
app.MapGet("/",?void?(HttpResponse?response)?=>?response.StatusCode?=?random.Next(400,599));
app.Run();static??Task?HandleErrorAsync(HttpContext?context)
{var?response?=?context.Response;return?response.StatusCode?<?500??response.WriteAsync($"Client?error?({response.StatusCode})"):?response.WriteAsync($"Server?error?({response.StatusCode})");
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281403.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281403.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281403.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringMVC接受JSON參數詳解及常見錯誤總結我改

SpringMVC接受JSON參數詳解及常見錯誤總結 最近一段時間不想使用Session了&#xff0c;想感受一下Token這樣比較安全&#xff0c;穩健的方式&#xff0c;順便寫一個統一的接口給瀏覽器還有APP。所以把一個練手項目的前臺全部改成Ajax了&#xff0c;跳轉再使用SpringMVC控制轉發…

軟件定義存儲的定制化怎么走?

引言 當前&#xff0c;軟件定義存儲成為業內超高速增長的典型。有研究人員稱&#xff0c;從2014年到2019年&#xff0c;軟件定義存儲市場將從14億美元增長到62億美元以上&#xff0c;年復合增長率將達35%。軟件定義存儲所帶來的優勢顯而易見&#xff0c;但是對于企業來說&#…

Golang并發模型:合理退出并發協程

goroutine作為Golang并發的核心&#xff0c;我們不僅要關注它們的創建和管理&#xff0c;當然還要關注如何合理的退出這些協程&#xff0c;不&#xff08;合理&#xff09;退出不然可能會造成阻塞、panic、程序行為異常、數據結果不正確等問題。這篇文章介紹&#xff0c;如何合…

劍網服務器維護,12月31日服務器例行維護公告

隱元秘鑒新增以下江湖行里使用趣味道具的成就&#xff1a;壓酒喚客嘗&#xff1a;使用壓酒三十次欲解紅燭意&#xff1a;使用燭影三十次閑情吹笛子&#xff1a;使用吹斷三十次引弦中落雀&#xff1a;使用千鳥三十次黃云動風色&#xff1a;使用風色三十次卷抒平生意&#xff1a;…

一款 Windows 軟件快捷助手

WPF 開發的 Windows 軟件快捷助手Windows 軟件快捷助手作者&#xff1a;WPFDevelopersOrg - 驚鏵原文鏈接&#xff1a;https://github.com/WPFDevelopersOrg/SoftwareHelper框架使用.NET40&#xff1b;Visual Studio 2019;項目使用 MIT 開源許可協議&#xff1b;項目使用 MVV…

關于8位AD_DA轉換芯片的采樣率問題

關于使用Keil計算程序執行時間 打開Keil程序&#xff0c;進入“啟動/停止調試”界面。在需要暫停的地方設置斷點&#xff08;在該句程序前雙擊&#xff09;。在程序上方有一行工具欄&#xff1a;此工具欄分別代表復位、運行、停止、步進、步越、步出、運行到光標處等。 點擊運…

CYQ.Data 數據框架 V4.0 開源版本發布(源碼提供下載,秋色園V2.5版本標配框架)

說明的說明&#xff1a; 博客園團隊兩次移此文出首頁&#xff0c;說 這篇文章不屬于知識分享型文章&#xff0c;并且有廣告嫌疑。 本文的確屬于分享型文章&#xff0c;而且分享的知識點比其它文章都多很多&#xff0c;看看網友回復“謝謝分享”就知道是分享型文章了。 所謂廣告…

oracle 分組后取每組第一條數據

數據格式 分組取第一條的效果 sql SELECT * FROM (SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, test1.* FROM test1) WHERE rn 1 ;

永大服務器進去顯示字母,永大電梯服務器使用說明

永大電梯服務器使用說明2021-05-25一&#xff0e; 目的&#xff1a;用于工務交車前對MPU和XDR板進行調試。二&#xff0e; 對應作業&#xff1a;1-1對MPU電梯調試接線連接&#xff1a;1).對MPUGB2(A2)版電梯調試時(以及A2前版本)&#xff0c;接線情況如下&#xff1a;連接順序連…

樹莓派Zero 2 W(ubuntu-22.04)通過.NET6和libusb操作USB讀寫

有這個想法的初衷喜歡電子和DIY硬件的朋友對稚暉君應該都不陌生&#xff0c;他定期都會分享一些自己做的好玩的硬件&#xff0c;他之前做了一個ElectronBot桌面機器人我就很感興趣&#xff0c;所以就自己也做了一個。起初我只是自己開發了一個叫電子腦殼的上位機軟件&#xff0…

bzoj4589

fwt 原理并不知道 nim游戲石子異或和0后手贏 那么也就是求a[1]^a[2]^...^a[n]0的方案數 這個和bzoj3992一樣可以dp dp[i][j]表示前i個數異或和為j的方案數 dp[0][0] 1 dp[i][j] dp[i - 1][k] * a[p] p ^ k j a[p] 0 / 1 表示有沒有p這個數 這個東西也不能矩陣快速冪 但是我…

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 85

UnicodeDecodeError: ascii codec cant decode byte 0xe5 in position 85;import sys reload(sys) sys.setdefaultencoding(utf8)

JS設計模式五:職責鏈模式

職責鏈模式簡述 職責連是由多個不同的對象組成的&#xff0c;有發送者跟接收者&#xff0c;分別負責信息的發送跟接收&#xff0c;其中&#xff0c;鏈中第一個對象是 職責連是由多個不同的對象組成的&#xff0c;發送者是發送請求的對象&#xff0c;接收者接收請求并且對其進行…

web框架之Django(一)

Python的WEB框架有Django、Tornado、Flask 等多種&#xff0c;Django相較與其他WEB框架其優勢為&#xff1a;大而全&#xff0c;框架本身集成了ORM、模型綁定、模板引擎、緩存、Session等諸多功能。 基本配置 一、創建django程序 終端命令&#xff1a;django-admin startprojec…

寫一個易于維護使用方便性能可靠的Hybrid框架(一)—— 思路構建

寫一個易于維護使用方便性能可靠的Hybrid框架&#xff08;二&#xff09;—— 插件化 寫一個易于維護使用方便性能可靠的Hybrid框架&#xff08;三&#xff09;—— 配置插件 前言 本來上一篇博文寫完&#xff0c;我就告訴自己&#xff0c;這是最后一篇&#xff0c;之后不再總結…

程序員制作出價值5億外賣神器卻不能取消訂單,你知道嗎?

小編今日給大家帶來RACDisopsable&#xff0c;大家可能有部分人對這個會感覺到很陌生&#xff0c;那么我就用一句話來表達就是他可以幫我們取消訂閱。那么又會有人會對這個產生疑問了&#xff0c;我們什么時候需要用到這個取消訂閱了打個實際的例子來說吧&#xff0c;今天我在餓…

Computer

鏈接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2196https://blog.csdn.net/shuangde800/article/details/9732825#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<queue> #include<cmath&…

智慧“昆明”在路上 未來充滿精彩

智慧城市是運用物聯網、云計算、大數據、移動互聯網、空間地理信息集成等新一代信息技術&#xff0c;促進城市規劃、建設、管理和服務智慧化的新理念和新模式。近年來&#xff0c;昆明市全面加快智慧城市建設&#xff0c;力爭通過三年的努力&#xff0c;打造區域信息輻射中心的…

《精讀 Mastering ABP Framework》教程發布

精讀《Mastering ABP Framework》學習總結&#xff0c;掌握軟件開發最佳實踐&#xff0c;構建可維護 .NET 解決方案。從 ABP Framework 框架中學習如何構建現代 WEB 應用程序。掌握 ABP Framework 框架ABP Framework 是一個完整的基礎架構&#xff0c;遵循軟件開發最佳實踐&…

C# 委托知識總結

1.什么是委托&#xff0c;為什么要使用委托 我正在埋頭苦寫程序&#xff0c;突然想喝水&#xff0c;但是又不想自己去掉杯水而打斷自己的思路&#xff0c;于是我就想讓女朋友去給我倒水。她去給我倒水&#xff0c;首先我得讓她知道我想讓她干什么&#xff0c;通知她之后我可以繼…