带有 JSON 的自定义 404 页面,没有重定向

Posted

技术标签:

【中文标题】带有 JSON 的自定义 404 页面,没有重定向【英文标题】:Custom 404 page with JSON without redirect 【发布时间】:2019-02-03 17:51:12 【问题描述】:

我正在开发一个 API,目前所有页面都返回 JSON,除了 404 页面,它是默认的 ASP.Net 404 页面。我想更改它,以便它在 404 页面上也返回 JSON。像这样的:

"Error":"Code":1234,"Status":"Invalid Endpoint"

如果我在 Global.asax.cs 文件中捕获 404 错误并重定向到现有路由,我可以获得类似的效果:

// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)

    Exception ex = Server.GetLastError();
    if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
    
        Response.Redirect("/CatchAll");
    


// file: HomeController.cs
[Route("CatchAll")]
public ActionResult UnknownAPIURL()

    return Content("\"Error\":\"Code\":1234,\"Status\":\"Invalid Endpoint\"", "application/json");

但这会向新 URL 返回一个 302 HTTP 代码,这不是我想要的。 我想在正文中返回一个带有 JSON 的 404 HTTP 代码。我该怎么做?

我尝试过的方法都没有用...

#1 - 覆盖默认错误页面

我想也许我可以覆盖 404 处理程序中的默认错误页面。我试过这样:

// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)

    Exception ex = Server.GetLastError();
    if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
    
        Response.Clear();
        Response.StatusCode = 404;
        Response.TrySkipIisCustomErrors = true;
        Response.AddHeader("content-type", "application/json");
        Response.Write("\"Error\":\"Code\":1234,\"Status\":\"Invalid Endpoint\"");
    

但它只是继续提供默认的 ASP 错误页面。顺便说一句,我根本没有修改我的web.config 文件。

#2 - 使用“包罗万象”的路线

我尝试在路由表的末尾添加一条“包罗万象”的路由。我的整个路线配置现在看起来像这样:

// file: RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)

    routes.IgnoreRoute("resource.axd/*pathInfo");

    routes.MapMvcAttributeRoutes();

    routes.MapRoute(
        name: "Default",
        url: "controller/action/id",
        defaults: new  controller = "Home", action = "Index", id = UrlParameter.Optional 
    );

    routes.MapRoute(
        name: "NotFound",
        url: "*data",
        defaults: new  controller = "Home", action = "CatchAll", data = UrlParameter.Optional 
    );

但这也不起作用。如果我在Application_Error() 中放置一个断点,我可以看到它仍然以 404 错误代码结束。我不确定这怎么可能,因为应该匹配所有路线?但无论如何,它永远不会到达包罗万象的路线。

#3 - 在运行时添加路由

我在另一个 SO 问题上看到了 this answer,在该问题上可以从错误处理程序中调用新路由。所以我尝试了:

// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)

    Exception ex = Server.GetLastError();
    if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
    
        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "Home");
        routeData.Values.Add("action", "CatchAll");

        Server.ClearError();
        Response.Clear();
        IController homeController = new HomeController();
        homeController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    

但是它给出了以下错误:

System.Web.Mvc.dll 中出现“System.Web.HttpException”类型的异常,但未在用户代码中处理

附加信息:在控制器 Myproject.Controllers.HomeController 上找不到公共操作方法“CatchAll”。

控制器肯定有这个方法。我正在使用 POST 调用 API,但是我尝试通过在方法前添加 [HttpPost] 来制作专门用于发布的控制器,但我仍然遇到相同的错误。

【问题讨论】:

【参考方案1】:

我们在路由表的末尾有一条包罗万象的路由,看起来有点像

        config.Routes.MapHttpRoute(
            name: "NotImplemented",
            routeTemplate: "*data",
            defaults: new  controller = "Error", action = "notimplemented", data = UrlParameter.Optional );

我们生成自定义响应的地方。您也许可以在路由表中执行类似的操作。

【讨论】:

我试过这个,但这条新路线永远不会被击中。相反,Application_Error() 函数会拦截调用。我会将此信息添加到问题中。【参考方案2】:

我终于找到了一个可行的解决方案。它基本上是上面的#1,添加了一个额外的行:

// file: Global.asax.cs
protected void Application_Error(object sender, EventArgs e)

    Exception ex = Server.GetLastError();
    if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
    
        Server.ClearError(); // important!!!
        Response.Clear();
        Response.StatusCode = 404;
        Response.TrySkipIisCustomErrors = true;
        Response.AddHeader("content-type", "application/json");
        Response.Write("\"Error\":\"Code\":1234,\"Status\":\"Invalid Endpoint\"");
    

Server.ClearError(); 命令似乎非常重要。没有它,将返回常规的 ASP 错误页面,并且 Response. 方法都不会对返回的数据产生任何影响。

【讨论】:

以上是关于带有 JSON 的自定义 404 页面,没有重定向的主要内容,如果未能解决你的问题,请参考以下文章

PHP中的自定义404错误页面

如何使用基于 404 错误的 mod_rewrite 重定向到自定义错误页面

自定义404页面重定向,但不显示自定义页面

如何使用 Codeigniter 在自定义 404 页面中重定向 404 错误?

如何在 Rails 中重定向到 404?

404错误页面未使用htaccess重定向到自定义页面