代码之家  ›  专栏  ›  技术社区  ›  mulllhausen

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

  •  0
  • mulllhausen  · 技术社区  · 7 年前

    我正在开发一个API,到目前为止,除了404页面(默认值)之外,所有页面都返回JSONASP.Net404页。我想更改它,以便它在404页上也返回JSON。像这样:

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

    如果我在全局.asax.cs文件并重定向到现有路由:

    // 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代码,这不是我想要的。 我想返回一个404http代码,其中的主体是JSON。我该怎么做?

    我尝试过的东西,但没有成功。。。

    #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)
        {
            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-使用“全包”路线

    我尝试在routes表的末尾添加一个“catch all”路由。我的整个路由配置现在看起来是这样的:

    // 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-在运行时添加路由

    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));
        }
    }
    

    Myproject.Controllers.HomeController .

    [HttpPost] 以前的方法,我仍然得到同样的错误。

    2 回复  |  直到 7 年前
        1
  •  0
  •   No Refunds No Returns    7 年前

    我们在路由表的末尾有一个catch all route,看起来有点像

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

    生成自定义响应。您可以在路由表中执行类似的操作。

        2
  •  0
  •   mulllhausen    7 年前

    // 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.