【问题标题】:Custom Selective 404 Page in MVC6MVC6 中的自定义选择性 404 页面
【发布时间】:2016-04-23 16:20:17
【问题描述】:

我正在寻求帮助,我们可以在 ASP.NET 5 MVC6 中创建自定义 Error404 页面。

我最接近的是使用

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

在 Startup.cs 的配置方法中。

通过调用“/Error/404”操作可以正常工作。

我正在研究如何在缺少 JPG/PNG/GIF 请求的情况下发送不同的 404 响应。

任何正确方向的建议都会有很大帮助。

【问题讨论】:

标签: asp.net-core asp.net-core-mvc


【解决方案1】:

如果您使用当前的 UseStatusCodePages 中间件,它将影响每一个错误。为了完成您要查找的内容,您需要创建自己的中间件,该中间件需要放置在您的默认错误处理中间件之后:

//Startup.cs
public void Configure(IApplicationBuilder app)
{
    app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
    app.UseImageNotFoundMiddlewareWithRedirect("/Home/ImageError");
}

这应该可以帮助您入门:Github - StatusCodePage

这是一个示例中间件,可以模拟您正在寻找的东西:

public class ImageNotFoundMiddleware
{
    private readonly RequestDelegate _next;
    private readonly StatusCodePagesOptions _options;

    public ImageNotFoundMiddleware(RequestDelegate next, IOptions<StatusCodePagesOptions> options)
    {
        _next = next;
        _options = options.Value;
        if (_options.HandleAsync == null)
        {
            throw new ArgumentException("Missing options.HandleAsync implementation.");
        }
    }

    public async Task Invoke(HttpContext context)
    {
        var statusCodeFeature = new StatusCodePagesFeature();
        context.Features.Set<IStatusCodePagesFeature>(statusCodeFeature);

        await _next(context);

        if (!statusCodeFeature.Enabled)
        {
            // Check if the feature is still available because other middleware (such as a web API written in MVC) could
            // have disabled the feature to prevent HTML status code responses from showing up to an API client.
            return;
        }

        // Do nothing if a response body has already been provided or not 404 response
        if (context.Response.HasStarted
            || context.Response.StatusCode != 404
            || context.Response.ContentLength.HasValue
            || !string.IsNullOrEmpty(context.Response.ContentType))
        {
            return;
        }

        // todo => Here is where you'd also add your logic to check for the image 404...
        if (context.Request.Path.Value.EndsWith(".JPG", StringComparison.OrdinalIgnoreCase)
            || context.Request.Path.Value.EndsWith(".PNG", StringComparison.OrdinalIgnoreCase)
            || context.Request.Path.Value.EndsWith(".GIF", StringComparison.OrdinalIgnoreCase)
            )
        {
            var statusCodeContext = new StatusCodeContext(context, _options, _next);
            await _options.HandleAsync(statusCodeContext);
        }
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class ImageNotFoundMiddlewareExtensions
{
    public static IApplicationBuilder UseImageNotFoundMiddlewareWithRedirect(this IApplicationBuilder app,
        string locationFormat)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<ImageNotFoundMiddleware>(
            Options.Create(
                new StatusCodePagesOptions
                {
                    HandleAsync = context =>
                    {
                        var location = string.Format(
                            CultureInfo.InvariantCulture,
                            locationFormat.StartsWith("~") ? locationFormat.Substring(1) : locationFormat,
                            context.HttpContext.Response.StatusCode);
                        context.HttpContext.Response.Redirect(
                            locationFormat.StartsWith("~")
                                ? context.HttpContext.Request.PathBase + location
                                : location);
                        return Task.FromResult(0);
                    }
                }
            )
        );
    }
}

【讨论】:

    【解决方案2】:

    作为自定义中间件方法的替代方案,您可以使用 MapWhen 来拆分管道并分别处理图像:

    将以下内容添加到 Startup.cs 的 Configure 方法(在您的非图像中间件之上):

    app.MapWhen(context => context.Request.Path.Value.EndsWith(".png"), appBuilder =>
    {
        appBuilder.UseStatusCodePagesWithReExecute("/image-error");
        appBuilder.UseStaticFiles();
    });
    

    显然,您可以更改谓词以满足您的需要。

    然后你可以创建一个动作和视图来处理错误:

    [Route("image-error")]
    public IActionResult ImageError(int code)
    {
        return View();
    }
    

    你可以在我写的关于conditional middleware的帖子中找到更多信息

    【讨论】:

      【解决方案3】:

      您应该能够使用 UseStatusCodePages() 方法的覆盖之一来实现此目的。使用其中之一:

      public class Startup
      {
          public void Configure(IApplicationBuilder app)
          {
              // app.UseErrorPage(ErrorPageOptions.ShowAll);
              // app.UseStatusCodePages();
              // app.UseStatusCodePages(context => context.HttpContext.Response.SendAsync("Handler, status code: " + context.HttpContext.Response.StatusCode, "text/plain"));
              // app.UseStatusCodePages("text/plain", "Response, status code: {0}");
              // app.UseStatusCodePagesWithRedirects("~/errors/{0}");
              // app.UseStatusCodePagesWithRedirects("/base/errors/{0}");
              // app.UseStatusCodePages(builder => builder.UseWelcomePage());
              // app.UseStatusCodePagesWithReExecute("/errors/{0}");
          }
      } 
      

      【讨论】:

      • 您能告诉我您发布的代码是如何解决我的问题的吗?
      猜你喜欢
      • 2018-11-16
      • 2017-09-23
      • 2016-05-14
      • 1970-01-01
      • 2013-09-16
      • 2010-11-04
      • 2012-10-26
      • 2011-08-05
      相关资源
      最近更新 更多