国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現“定制化錯誤頁面”

來源:懂視網 責編:小采 時間:2020-11-27 22:34:42
文檔

ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現“定制化錯誤頁面”

ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現定制化錯誤頁面:前言 DeveloperExceptionPageMiddleware中間件利用呈現出來的錯誤頁面實現拋出異常和當前請求的詳細信息以輔助開發人員更好地進行糾錯診斷工作,而ExceptionHandlerMiddleware中間件則是面向最終用戶的,我們可以利用它來顯示一個友好的定制化的錯誤頁面。按
推薦度:
導讀ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現定制化錯誤頁面:前言 DeveloperExceptionPageMiddleware中間件利用呈現出來的錯誤頁面實現拋出異常和當前請求的詳細信息以輔助開發人員更好地進行糾錯診斷工作,而ExceptionHandlerMiddleware中間件則是面向最終用戶的,我們可以利用它來顯示一個友好的定制化的錯誤頁面。按

前言

DeveloperExceptionPageMiddleware中間件利用呈現出來的錯誤頁面實現拋出異常和當前請求的詳細信息以輔助開發人員更好地進行糾錯診斷工作,而ExceptionHandlerMiddleware中間件則是面向最終用戶的,我們可以利用它來顯示一個友好的定制化的錯誤頁面。按照慣例,我們還是先來看看ExceptionHandlerMiddleware的類型定義。

 public class ExceptionHandlerMiddleware
 { 
 public ExceptionHandlerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<ExceptionHandlerOptions> options, DiagnosticSource diagnosticSource); 
 public Task Invoke(HttpContext context);
 }
 
 public class ExceptionHandlerOptions
 {
 public RequestDelegate ExceptionHandler { get; set; }
 public PathString ExceptionHandlingPath { get; set; }
 }

與DeveloperExceptionPageMiddleware類似,我們在創建一個ExceptionHandlerMiddleware對象的時候同樣需要提供一個攜帶配置選項的對象,從上面的代碼可以看出這是一個ExceptionHandlerOptions。具體來說,一個ExceptionHandlerOptions對象通過其ExceptionHandler屬性提供了一個最終用來處理請求的RequestDelegate對象。如果希望發生異常后自動重定向到某個指定的路徑,我們可以利用ExceptionHandlerOptions對象的ExceptionHandlingPath屬性來指定這個路徑。我們一般會調用ApplicationBuilder的擴展方法UseExceptionHandler來注冊ExceptionHandlerMiddleware中間件,這些重載的UseExceptionHandler方法會采用如下的方式完整中間件的注冊工作。

 public static class ExceptionHandlerExtensions
 {
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app)=> app.UseMiddleware<ExceptionHandlerMiddleware>();
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, ExceptionHandlerOptions options) 
 => app.UseMiddleware<ExceptionHandlerMiddleware>(Options.Create(options));
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, string errorHandlingPath)
 { 
 return app.UseExceptionHandler(new {
 ExceptionHandlingPath = new PathString(errorHandlingPath)
 });
 }
 
 public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, Action<IApplicationBuilder> configure)
 {
 IApplicationBuilder newBuilder = app.New();
 configure(newBuilder);
 
 return app.UseExceptionHandler(new ExceptionHandlerOptions
 {
 ExceptionHandler = newBuilder.Build()
 });
 } 
 }

一、異常處理器

ExceptionHandlerMiddleware中間件處理請求的本質就是在后續請求處理過程中出現異常的情況下采用注冊的異常處理器來處理并響應請求,這個異常處理器就是我們再熟悉不過的RequestDelegate對象。該中間件采用的請求處理邏輯大體上可以通過如下所示的這段代碼來體現。

 public class ExceptionHandlerMiddleware
 {
 private RequestDelegate _next;
 private ExceptionHandlerOptions _options;
 
 public ExceptionHandlerMiddleware(RequestDelegate next, IOptions<ExceptionHandlerOptions> options,…)
 {
 _next = next;
 _options = options.Value;
 …
 }
 
 public async Task Invoke(HttpContext context)
 {
 try
 {
 await _next(context);
 }
 catch 
 {
 context.Response.StatusCode = 500;
 context.Response.Clear();
 if (_options.ExceptionHandlingPath.HasValue)
 {
 context.Request.Path = _options.ExceptionHandlingPath;
 }
 RequestDelegate handler = _options.ExceptionHandler ?? _next;
 await handler(context);
 }
 }
 }

如上面的代碼片段所示,如果后續的請求處理過程中出現異常,ExceptionHandlerMiddleware中間件會利用一個作為異常處理器的RequestDelegate對象來完成最終的請求處理工作。如果在創建ExceptionHandlerMiddleware時提供的ExceptionHandlerOptions攜帶著這么一個RequestDelegate對象,那么它將作為最終使用的異常處理器,否則作為異常處理器的實際上就是后續的中間件。換句話說,如果我們沒有通過ExceptionHandlerOptions顯式指定一個異常處理器,ExceptionHandlerMiddleware中間件會在后續管道處理請求拋出異常的情況下將請求再次傳遞給后續管道。

當ExceptionHandlerMiddleware最終利用異常處理器來處理請求之前,它會對請求做一些前置處理工作,比如它會將響應狀態碼設置為500,比如清空當前所有響應內容等。如果我們利用ExceptionHandlerOptions的ExceptionHandlingPath屬性設置了一個重定向路徑,它會將該路徑設置為當前請求的路徑。除了這些,ExceptionHandlerMiddleware中間件實際上做了一些沒有反應在上面這段代碼片段中的工作。

二、異常的傳遞與請求路徑的恢復

由于ExceptionHandlerMiddleware中間件總會利用一個作為異常處理器的RequestDelegate對象來完成最終的異常處理工作,為了讓后者能夠得到拋出的異常,該中間件應該采用某種方式將異常傳遞給它。除此之外,由于ExceptionHandlerMiddleware中間件會改變當前請求的路徑,當整個請求處理完成之后,它必須將請求路徑恢復成原始的狀態,否則前置的中間件就無法獲取到正確的請求路徑。

請求處理過程中拋出的異常和原始請求路徑的恢復是通過相應的特性完成的。具體來說,傳遞這兩者的特性分別叫做ExceptionHandlerFeature和ExceptionHandlerPathFeature,對應的接口分別為IExceptionHandlerFeature和IExceptionHandlerPathFeature,如下面的代碼片段所示,后者繼承前者。默認使用的ExceptionHandlerFeature實現了這兩個接口。

 public interface IExceptionHandlerFeature
 {
 Exception Error { get; }
 }
 
 public interface IExceptionHandlerPathFeature : IExceptionHandlerFeature
 {
 string Path { get; }
 }
 
 public class ExceptionHandlerFeature : IExceptionHandlerPathFeature, 
 {
 public Exception Error { get; set; }
 public string Path { get; set; }
 }

當ExceptionHandlerMiddleware中間件將代碼當前請求的HttpContext傳遞給請求處理器之前,它會按照如下所示的方式根據拋出的異常的原始的請求路徑創建一個ExceptionHandlerFeature對象,該對象最終被添加到HttpContext之上。當整個請求處理流程完全結束之后,ExceptionHandlerMiddleware中間件會借助這個特性得到原始的請求路徑,并將其重新應用到當前請求上下文上。

 public class ExceptionHandlerMiddleware
 {
 ...
 public async Task Invoke(HttpContext context)
 {
 try
 {
 await _next(context);
 }
 catch(Exception ex)
 {
 context.Response.StatusCode = 500;
 
 var feature = new ExceptionHandlerFeature()
 {
 Error = ex,
 Path = context.Request.Path,
 };
 context.Features.Set<IExceptionHandlerFeature>(feature);
 context.Features.Set<IExceptionHandlerPathFeature>(feature);
 
 if (_options.ExceptionHandlingPath.HasValue)
 {
 context.Request.Path = _options.ExceptionHandlingPath;
 }
 RequestDelegate handler = _options.ExceptionHandler ?? _next;
 
 try
 {
 await handler(context);
 }
 finally
 {
 context.Request.Path = originalPath;
 }
 }
 }
 }

在具體進行異常處理的時候,我們可以從當前HttpContext中提取這個ExceptionHandlerFeature對象,進而獲取拋出的異常和原始的請求路徑。如下面的代碼所示,我們利用HandleError方法來呈現一個定制的錯誤頁面。在這個方法中,我們正式借助于這個ExceptionHandlerFeature特性得到拋出的異常,并將它的類型、消息以及堆棧追蹤顯示出來。

 public class Program
 {
 public static void Main()
 {
 new WebHostBuilder()
 .UseKestrel()
 .ConfigureServices(svcs=>svcs.AddRouting())
 .Configure(app => app
 .UseExceptionHandler("/error")
 .UseRouter(builder=>builder.MapRoute("error", HandleError))
 .Run(context=> Task.FromException(new InvalidOperationException("Manually thrown exception"))))
 .Build()
 .Run();
 }
 
 private async static Task HandleError(HttpContext context)
 {
 context.Response.ContentType = "text/html";
 Exception ex = context.Features.Get<IExceptionHandlerPathFeature>().Error;
 
 await context.Response.WriteAsync("<html><head><title>Error</title></head><body>");
 await context.Response.WriteAsync($"<h3>{ex.Message}</h3>");
 await context.Response.WriteAsync($"<p>Type: {ex.GetType().FullName}");
 await context.Response.WriteAsync($"<p>StackTrace: {ex.StackTrace}");
 await context.Response.WriteAsync("</body></html>");
 }

在上面這個應用中,我們注冊了一個模板為“error”的路由指向這個HandleError方法。對于通過調用擴展方法UseExceptionHandler注冊的ExceptionHandlerMiddleware來說,我們將該路徑設置為異常處理路徑。那么對于任意從瀏覽器發出的請求,都會得到如下圖所示的錯誤頁面。

三、清除緩存

對于一個用于獲取資源的GET請求來說,如果請求目標是一個相對穩定的資源,我們可以采用客戶端緩存的方式避免相同資源的頻繁獲取和傳輸。對于作為資源提供者的Web應用來說,當它在處理請求的時候,除了將目標資源作為響應的主體內容之外,它還需要設置用于控制緩存的相關響應報頭。由于緩存在大部分情況下只適用于成功的響應,如果服務端在處理請求過程中出現異常,之前設置的緩存報頭是不應該出現在響應報文中。對于ExceptionHandlerMiddleware中間件來說,清楚緩存報頭也是它負責的一項重要工作。

我們同樣可以通過一個簡單的實例來演示ExceptionHandlerMiddleware中間件針對緩存響應報頭的清除。在如下這個應用中,我們將針對請求的處理實現在Invoke方法中,它有50%的可能會拋出異常。不論是返回正常的響應內容還是拋出異常,這個方法都會先設置一個“Cache-Control”的響應報頭,并將緩存時間設置為1個小時(“Cache-Control: max-age=3600”)。

 public class Program
 {
 public static void Main()
 {
 new WebHostBuilder()
 .UseKestrel()
 .ConfigureServices(svcs => svcs.AddRouting())
 .Configure(app => app
 .UseExceptionHandler(builder => builder.Run(async context => await context.Response.WriteAsync("Error occurred!")))
 .Run(Invoke))
 .Build()
 .Run();
 }
 
 private static Random _random = new Random();
 private async static Task Invoke(HttpContext context)
 {
 context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue
 {
 MaxAge = TimeSpan.FromHours(1)
 };
 
 if (_random.Next() % 2 == 0)
 {
 throw new InvalidOperationException("Manually thrown exception...");
 }
 await context.Response.WriteAsync("Succeed...");
 }
 }

通過調用擴展方法 UseExceptionHandler注冊的ExceptionHandlerMiddleware中間件在處理異常時會響應一個內容為“Error occurred!”的字符串。如下所示的兩個響應報文分別對應于正常響應和拋出異常的情況,我們會發現程序中設置的緩存報頭“Cache-Control: max-age=3600”只會出現在狀態碼為“200 OK”的響應中。至于狀態碼為“500 Internal Server Error”的響應中,則會出現三個與緩存相關的報頭,它們的目的都會為了禁止緩存(或者指示緩存過期)。

 HTTP/1.1 200 OK
 Date: Sat, 17 Dec 2016 14:39:02 GMT
 Server: Kestrel
 Cache-Control: max-age=3600
 Content-Length: 10
 
 Succeed...
 
 
 HTTP/1.1 500 Internal Server Error
 Date: Sat, 17 Dec 2016 14:38:39 GMT
 Server: Kestrel
 Cache-Control: no-cache
 Pragma: no-cache
 Expires: -1
 Content-Length: 15
 
 Error occurred!

ExceptionHandlerMiddleware中間件針對緩存響應報頭的清除體現在如下所示的代碼片段中。我們可以看出它通過調用HttpResponse的OnStarting方法注冊了一個回調(ClearCacheHeaders),上述的這三個緩存報頭在這個回調中設置的。除此之外,我們還看到這個回調方法還會清除ETag報頭,這也很好理解:由于目標資源沒有得到正常的響應,表示資源“簽名”的ETag報頭自然不應該出現在響應報文中。

 public class ExceptionHandlerMiddleware
 {
 ...
 public async Task Invoke(HttpContext context)
 {
 try
 {
 await _next(context);
 }
 catch (Exception ex)
 {
 …
 context.Response.OnStarting(ClearCacheHeaders, context.Response);
 RequestDelegate handler = _options.ExceptionHandler ?? _next;
 await handler(context);
 }
 }
 
 private Task ClearCacheHeaders(object state)
 {
 var response = (HttpResponse)state;
 response.Headers[HeaderNames.CacheControl] = "no-cache";
 response.Headers[HeaderNames.Pragma] = "no-cache";
 response.Headers[HeaderNames.Expires] = "-1";
 response.Headers.Remove(HeaderNames.ETag);
 return Task.CompletedTask;
 }
 }

總結

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現“定制化錯誤頁面”

ASP.NET Core應用錯誤處理之ExceptionHandlerMiddleware中間件呈現定制化錯誤頁面:前言 DeveloperExceptionPageMiddleware中間件利用呈現出來的錯誤頁面實現拋出異常和當前請求的詳細信息以輔助開發人員更好地進行糾錯診斷工作,而ExceptionHandlerMiddleware中間件則是面向最終用戶的,我們可以利用它來顯示一個友好的定制化的錯誤頁面。按
推薦度:
標簽: 中間 錯誤 呈現
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 国产片欧美片亚洲片久久综合 | 国产精品视频播放 | 免费又黄又爽又猛大片午夜 | 国产91免费视频 | 久久99九九精品免费 | 国内精品线在线观看 | 婷婷成人亚洲 | 欧美日本日韩aⅴ在线视频 欧美日韩91 | 亚洲色图另类 | 国产区精品 | 天堂va欧美ⅴa亚洲va一国产 | 欧美国产日韩一区二区三区 | 日韩电影免费在线观看中文字幕 | 欧美日韩亚洲综合另类ac | 精品久久一区二区 | 国产人澡人澡澡澡人碰视频 | 亚洲欧美日韩精品久久久 | 最新国产在线播放 | 午夜视频hd | 精品精品国产高清a毛片牛牛 | 欧美日韩国产片 | 亚洲欧美日韩网站 | 国产免费高清视频在线观看不卡 | 亚洲好骚综合 | 在线欧美v日韩v国产精品v | 国产高清一区二区三区 | 日韩欧美高清一区 | 999久久久免费精品国产牛牛 | 日韩在线1| 麻豆国产 | 九九精品成人免费国产片 | 国内精品一区二区 | 99热只有精品一区二区 | 国产a视频 | 日本韩国一区二区 | 欧美精品午夜久久久伊人 | 欧美v在线| 国产在线91区精品 | 国产一区亚洲欧美成人 | 与子乱刺激对白在线播放 | 中文字幕有码在线播放 |