問(wèn)題
為黃州等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及黃州網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、黃州網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
在沒(méi)有修改任何配置的情況下,這是用戶(hù)使用 Chrome 訪問(wèn)不存在的URL時(shí)會(huì)看到的內(nèi)容:
幸運(yùn)的是,處理錯(cuò)誤狀態(tài)代碼非常簡(jiǎn)單,我們將在下面介紹三種技術(shù)。
解決方案
在以前的ASP.NET MVC版本中,主要在 web.config 中處理404錯(cuò)誤的。
您可能記得在
在.Net Core中,情況就不同了,沒(méi)有必要使用XML配置(盡管如果您是通過(guò)IIS代理,您仍然可以在web.config中使用 httpErrors,并且您真的想這樣嗎:-))。
在處理 not-found 錯(cuò)誤時(shí),我們需要處理兩種不同的情況。
URL與任何路由不匹配的情況。在這種情況下,如果我們無(wú)法確定用戶(hù)正在訪問(wèn)什么,我們需要返回一個(gè)通用的未找到的頁(yè)面。有兩種常見(jiàn)的處理方法,但首先我們將討論第二種情況。URL與路由匹配的情況,但是一個(gè)或多個(gè)參數(shù)無(wú)效,我們可以用自定義視圖來(lái)解決這個(gè)問(wèn)題。
自定義視圖
這種情況的一個(gè)例子是具有無(wú)效或過(guò)期ID的產(chǎn)品頁(yè)面。在這里,我們知道用戶(hù)正在查看產(chǎn)品,而不是返回通用錯(cuò)誤,我們可以更友好的頁(yè)面,返回自定義未找到產(chǎn)品的的頁(yè)面。這仍然需要返回404狀態(tài)代碼,但是使用不通用的頁(yè)面,同時(shí)也可以向用戶(hù)顯示類(lèi)似或受歡迎的產(chǎn)品。
處理這些情況是非?,嵥椋覀冃枰龅氖窃诜祷匚覀兊淖远x視圖之前設(shè)置狀態(tài)代碼:
public async TaskGetProduct(int id) { var viewModel = await _db.Get (id); if (viewModel == null) { Response.StatusCode = 404; return View("ProductNotFound"); } return View(viewModel); }
當(dāng)然,您可能更喜歡將其包裝成自定義ActionResult:
public class NotFoundViewResult : ViewResult { public NotFoundViewResult(string viewName) { ViewName = viewName; StatusCode = (int)HttpStatusCode.NotFound; } }
這簡(jiǎn)化了我們的Action:
public async TaskGetProduct(int id) { var viewModel = await _db.Get (id); if (viewModel == null) { return new NotFoundViewResult("ProductNotFound"); } return View(viewModel); }
這個(gè)簡(jiǎn)單的技術(shù)涵蓋了特定的404頁(yè),現(xiàn)在來(lái)看看通用的404錯(cuò)誤,我們無(wú)法弄清楚用戶(hù)想要查看的內(nèi)容。
通配路由
在先前版本的MVC,創(chuàng)建一個(gè)通配符路由來(lái)處理,在.NET Core中,也可以使用相同的方式。這個(gè)方式是,您有一個(gè)通配符路由,它會(huì)接收任何其它路由尚未處理的URL。使用特性路由,方式如下:
[Route("{*url}", Order = 999)] public IActionResult CatchAll() { Response.StatusCode = 404; return View(); }
重要的是指定順序,以確保其它路由優(yōu)先。
一個(gè)通配符路由的方式非常不錯(cuò),但它不是.NET Core中的首選。雖然全部路由將處理404,但下一個(gè)方式將處理任何非成功狀態(tài)代碼,以便您可以執(zhí)行以下Action(可能在生產(chǎn)中的Action過(guò)濾器中):
public async TaskGetProduct(int id) { ... if (RequiresThrottling()) { return new StatusCodeResult(429) } if (!HasPermission(id)) { return Forbid(); } ... }
StatusCodePagesWithReExecute方法 中件間
UseStatusCodePagesWithReExecute
使用了一個(gè)非常聰明的中間件(StatusCodePagesMiddleware
),在未輸出響應(yīng)前,它能處理非成功狀態(tài)代碼。這意味著如果您使用上面詳細(xì)描述的自定義視圖技術(shù),則404狀態(tài)代碼將不會(huì)被中間件處理(這正是我們想要的)。
當(dāng)從內(nèi)部中間件組件返回錯(cuò)誤代碼(如404)時(shí),UseStatusCodePagesWithReExecute
允許您執(zhí)行另一個(gè)控制器Action來(lái)處理狀態(tài)代碼。
您可以在startup.cs
中使用一行代碼將其添加到管道中:
app.UseStatusCodePagesWithReExecute("/error/{0}"); ... app.UseMvc();
中間件定義的順序很重要,您需要確保在可能返回錯(cuò)誤代碼的任何中間件(如MVC中間件)之前注冊(cè)StatusCodeWithReExecute
。
您可以指定一個(gè)固定路徑來(lái)執(zhí)行或使用狀態(tài)代碼值的占位符,如上所述。
您還可以指向靜態(tài)頁(yè)面(假設(shè)您已經(jīng)具有StaticFileMiddleware
中間件)和控制器Action。
在這個(gè)例子中,我們有一個(gè)單獨(dú)的Action處理404。任何其它非成功狀態(tài)代碼,使用 Error
Action。
[Route("error/404")] public IActionResult Error404() { return View(); } [Route("error/{code:int}")] public IActionResult Error(int code) { // handle different codes or just return the default error view return View(); }
顯然,您可以根據(jù)您的需要量身定制。例如,如果您正在使用上一節(jié)所示的請(qǐng)求限制,那么您可以返回一個(gè)解釋為什么請(qǐng)求失敗的429頁(yè)面。
總結(jié)
處理404頁(yè)面的具體問(wèn)題最好用自定義視圖來(lái)處理,并設(shè)置狀態(tài)代碼(直接或通過(guò)自定義操作結(jié)果)。
通過(guò)使用StatusCodePagesMiddleware
中間件,可以非常容易地處理通用404錯(cuò)誤(或?qū)嶋H上是任何非成功狀態(tài)代碼)。一般來(lái)說(shuō),這兩種技術(shù)是在ASP.NET Core中處理非成功HTTP狀態(tài)代碼的首選方法。
原文:《Handling 404 Not Found in Asp.Net Core》
翻譯:Sweet Tang