【问题标题】:How do I return json for 404s and 403s in WebAPI?如何在 WebAPI 中返回 404 和 403 的 json?
【发布时间】:2015-02-24 06:56:38
【问题描述】:

我有一个相当简单的 Web API 应用程序,目前有一个路由设置。如果用户尝试访问任何其他路由,他们会返回 404,但 404 的主体是 HTML 而不是 JSON(这是他们的接受标头所要求的)。让 IIS 使用 JSON 错误响应而不是网页来响应不存在路由的请求的最简单(添加到我的项目中的代码/配置最少)的方法是什么?

同样的问题也适用于 403。如果我尝试导航到我的应用程序的根目录,我会得到 403,再次作为网页返回。我希望这是一个 404,但更大的问题是如何使我的应用程序的 all 响应成为 JSON 而不仅仅是有效路由上的响应?我提到 403 是因为我正在寻找一个更广泛的解决方案,而不仅仅是设置一条包罗万象的路线,因为我认为这不会帮助我处理 403 或控制器操作之外发生的任何其他随机异常。

我希望我的应用程序尊重请求中的接受标头。然而,由于我的 API 目前只支持 JSON,我愿意(暂时)接受它总是以 JSON 响应。

我正在使用 WebAPI 2.2 和 .NET 4.5.2。

编辑

这不是格式化程序问题。格式化程序正确应用于成功的消息,尊重请求中的接受标头。这特别是未处理的路由和 Web 服务器错误(如尝试访问 Web 根目录时被禁止)的问题。

编辑 2

重现步骤:

  1. 打开 Visual Studio 2013 更新 4
  2. 新项目
  3. 选择 .NET Framework 4.5.2
  4. 选择模板 > Visual C# > Web > ASP.NET Web 应用程序
  5. 选择“空”,保留所有文件夹和核心引用未选中
  6. 右键单击项目 > 添加 > 新建脚手架项 > Web API 2 控制器 - 空
  7. 如下图修改DefaultController。
  8. 修改WebApiConfig.cs如下图。
  9. 运行/调试

我期望的是,当我导航到 http://localhost:<port>/api/do_stuff 时,我会在 XML 或 JSON 中看到 Success!,具体取决于接受标头(我会这样做),当我导航到任何其他页面时,我应该会看到 Failure!(其中我不)。相反,当我导航到任何其他页面时,我会看到 IIS 的 404 响应。

DefaultController.cs:

[RoutePrefix("api")]
public class DefaultController : ApiController
{
    [HttpGet]
    [Route("do_stuff")]
    public String DoStuff()
    {
        return "Success!";
    }
}

WebApiConfig.cs:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Filters.Add(new CustomExceptionFilter());
    }

    private class CustomExceptionFilter : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                actionExecutedContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.NotFound)
                {
                    Content = new StringContent(@"""Failure!"""),
                };
            }
        }
    }
}

编辑 3

我还尝试添加全局异常处理程序和异常记录器,如下所示: http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling

在上面的示例中,当我尝试导航到无效路线或导航到站点根目录时,两者都不会被调用。

【问题讨论】:

  • 如果接受标头是 text/html 而不是 application/json 那么返回 HTML 可能是正确的做法。
  • 我不相信这个答案在这里适用,因为接受标头当前设置为 application/json 但我正在返回 text/html。这意味着我的格式化程序没有因为丢失路由和被禁止的请求而受到尊重。
  • 虽然我会检查您提到的步骤并还原,但是您可以将 CustomExceptionFilter 设为独立的公共类吗,将其设为私有类有什么意义,我的理解是即使您注册了,它仅适用于 WebAPIConfig 内的异常,这就是为什么它不会触发遇到的任何异常
  • 使异常过滤器成为非嵌套的公共类并没有改变行为。出于设计/风格的原因,我将其设为私有,它不需要在 WebApiConfig 之外进行实例化或访问,因此将其公开只会污染命名空间。它实现了 IExceptionFilter,它是公共的,并且是被传递的。
  • 感谢您的验证,这似乎是 Web API 代码似乎没有被调用的情况,错误似乎是从 Web 服务器本身返回的,因为它无法获得有效的资源或有没有访问站点根目录的权限。我的理解是任何自定义代码异常都会被捕获,如果确实如此,那么我们已经偏离了主要问题。在这种情况下,异常过滤器无法处理此类情况,因为它需要在 Web API 执行中抛出异常

标签: c# asp.net asp.net-web-api


【解决方案1】:

调用 httpget 以获取响应 404 notfound 使用此

public JsonResult DoSomething() {
        try
        {

            var result = getData();
            return Json(result, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            return Json(HttpNotFound());
        }

    }

【讨论】:

  • 适用于 .NET 4.5.2 还是 .NET Core?
  • 它适用于 .NET 4.6.1
【解决方案2】:

从您计划的 catch-all-route 调用以下函数以返回如下所示的 jsonResult 操作

public JsonResult Handle404()
{
   return Json(new { error404 = "NOT FOUND", Message = "Additional Message" });
}

会产生

var result =
{
  "error404": "NOT FOUND",
  "Message": "Additional Message"
}; 

alert(result.error404);
allert(result.Message);

【讨论】:

  • 一条包罗万象的路线将明确解决 404,但是我的应用程序可能抛出的所有其他异常呢?一个易于重现的示例是当我尝试访问应用程序的根目录时得到的 403。其他可能包括 IIS 配置错误、应用程序配置错误、应用程序崩溃等。我知道我可能无法让 IIS 针对真正致命的错误(如内存不足)返回 JSON,但我希望所有可能的 JSON 响应。
猜你喜欢
  • 2013-06-16
  • 2011-11-08
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多