由于StatusCodePagesMiddleware中间件最终的目的还是将定制的错误信息响应给客户端,所以我们可以在注册该中间件的时候直接指定响应的内容和媒体类型,这样的注册方式可以通过调用如下这个UseStatusCodePages方法来完成。从如下所示的代码片段我们不难看出,我们通过bodyFormat方法指定的实际上是一个模板,它可以包含一个表示响应状态的占位符(“{0}”)。
public static class StatusCodePagesExtensions { public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app, string contentType, string bodyFormat) { return app.UseStatusCodePages(context => { var body = string.Format(CultureInfo.InvariantCulture, bodyFormat, context.HttpContext.Response.StatusCode); context.HttpContext.Response.ContentType = contentType; return context.HttpContext.Response.WriteAsync(body); }); } }
UseStatusCodePagesWithRedirects
如果我们调用UseStatusCodePagesWithRedirects方法,可以让注册的StatusCodePagesMiddleware中间件向指定的路径发送一个客户端重定向。从如下所示的实现代码可以看出,这个作为参数locationFormat的重定向地址也是一个模板,它可以包含一个表示响应状态的占位符(“{0}”)。我们可以指定一个完整的地址,也可以指定一个相对于PathBase的相对路径,后者需要包含表示基地址的“~/”前缀。
public static class StatusCodePagesExtensions { public static IApplicationBuilder UseStatusCodePagesWithRedirects(this IApplicationBuilder app, string locationFormat) { if (locationFormat.StartsWith("~")) { locationFormat = locationFormat.Substring(1); return app.UseStatusCodePages(context => { var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode); context.HttpContext.Response.Redirect(context.HttpContext.Request.PathBase + location); return Task.CompletedTask; }); } else { return app.UseStatusCodePages(context => { var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode); context.HttpContext.Response.Redirect(location); return Task.CompletedTask; }); } } }
我们通过一个简单的应用来演示针对客户端重定向的错误页面呈现方式。我们在如下这个应用中注册了一个路由模板为“error/{statuscode}”的路由,路由参数“statuscode”自然代表响应的状态码。在作为路由处理器的HandleError方法中,我们会直接响应一个包含响应状态码的字符串。我们调用UseStatusCodePagesWithRedirects方法注册StatusCodePagesMiddleware中间件的时候将重定义路径设置为“error/{0}”。
public class Program { private static Random _random = new Random(); public static void Main() { new WebHostBuilder() .UseKestrel() .ConfigureServices(svcs => svcs.AddRouting()) .Configure(app => app .UseStatusCodePagesWithRedirects("~/error/{0}") .UseRouter(builder=>builder.MapRoute("error/{statuscode}", HandleError)) .Run(context=>Task.Run(()=>context.Response.StatusCode = _random.Next(400,599)))) .Build() .Run(); } private async static Task HandleError(HttpContext context) { var statusCode = context.GetRouteData().Values["statuscode"]; await context.Response.WriteAsync($"Error occurred ({statusCode})"); } }
针对该应用的请求总是会得到一个状态码在400~599之间的响应, StatusCodePagesMiddleware在此情况下会向我们指定的路径(“~/error/{statuscode}”)发送一个客户端重定向。由于重定向请求的路径与注册的路由相匹配,所以作为路由处理器的HandleError方法会响应如图11所示的这个错误页面。
UseStatusCodePagesWithReExecute
除了采用客户端重定向的方式来呈现错误页面之外,我们还可以调用UseStatusCodePagesWithReExecute方法注册StatusCodePagesMiddleware中间件并让它采用服务端重定向的方式来处理错误请求。如下面的代码片段所示,当我们调用这个方法的时候不仅可以指定重定向的路径,还可以指定指定查询字符串。这里作为重定向地址的参数pathFormat依旧是一个路径模板,它可以包含一个表示响应状态的占位符(“{0}”)。
public static class StatusCodePagesExtensions { public static IApplicationBuilder UseStatusCodePagesWithReExecute(this IApplicationBuilder app, string pathFormat, string queryFormat = null); }
现在我们对上面演示的这个实例略作修改来演示采服务端重定向呈现出来的错误页面。如下面的代码片段所示,我们仅仅将针对UseStatusCodePagesWithRedirects方法的调用替换成针对UseStatusCodePagesWithReExecute方法的调用而已。