当使用ExceptionHandler PipeLine时,ASP.NET Core返回404而不是500。

11

我有这个控制器

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        Console.WriteLine("GET Index");
        throw new Exception();
    }

    // POST api/values
    [HttpPost]
    public void Post()
    {
        Console.WriteLine("POST Index");
        throw new Exception();
    }
}

GET和POST请求均返回状态码500。这是预期行为。

但是,当我在Startup.cs文件中添加app.UseExceptionHandler("/api/debug/error");时,POST请求不再返回状态码500,而是返回404。GET请求仍按预期工作,返回状态码500。

DebugController

[Route("api/[controller]")]
public class DebugController : Controller
{


    [HttpGet("error")]
    public IActionResult Index()
    {
        return StatusCode(500,"Hello, World! From debug controller");
    }
}

为什么添加 app.UseExceptionHandler("/api/debug/error"); 会使得 POST 请求表现出这种行为?

可以在这里找到重现此问题的存储库。


您遇到了获取错误,但没有处理 POST 错误的行动。 - Tratcher
2个回答

11

当使用ExceptionHandlerMiddleware和ExceptionHandlingPath一起时,就像你的示例中一样,主要的结果是请求路径被重写以使用你的新路径(在你的情况下是/api/debug/error)。你可以在source中看到它的工作原理:

if (_options.ExceptionHandlingPath.HasValue)
{
    context.Request.Path = _options.ExceptionHandlingPath;
}

如果您继续浏览源代码,您会看到StatusCode被设置为500, 但原始请求基本保持不变。
在实际应用中,这意味着您将被发送到DebugController的POST操作,但您只提供了GET操作。
修复此问题的简单方法是使您的Index操作同时支持GETPOST,如下所示:
[HttpGet("error")]
[HttpPost("error")]
public IActionResult Index()
{
    return StatusCode(500,"Hello, World! From debug controller");
}

如果你想对POST错误做一些不同的处理,你可以创建一个新的动作,并用[HttpPost("error")]进行装饰。
更新:现在docs中已经存在这些解释:
异常处理中间件会使用原始的HTTP方法重新执行请求。如果错误处理端点仅限于特定的HTTP方法,则仅对这些HTTP方法运行。例如,使用[HttpGet]属性的MVC控制器操作仅适用于GET请求。为确保所有请求都到达自定义错误处理页面,请不要将它们限制为特定的HTTP方法集。
要根据原始HTTP方法以不同方式处理异常:
  • 对于Razor Pages,请创建多个处理程序方法。例如,使用OnGet处理GET异常,使用OnPost处理POST异常。
  • 对于MVC,请将HTTP动词属性应用于多个操作。例如,使用[HttpGet]处理GET异常,使用[HttpPost]处理POST异常。

0

我认为我遇到了类似的问题。我创建了一个可从JavaScript调用的API控制器。在开发过程中一切都正常。但是我已经注意到,在现场网站上,API经常返回404错误,即使路由显然存在。

我认为我已经找到了问题所在,这是由于现场网站上微妙差异引起的500错误,尤其是在现场和开发环境中使用不同版本的SQL数据库。因此,基本上我的API的GET方法应该返回500,而不是404。解决方案似乎是确保我的API方法具有[HttpGet]和[HttpPost]属性。

我还注意到另一个问题是,如果您使用以下内容,则有时会缓存API调用:

app.UseResponseCaching();

在 Startup.cs 文件中。这非常取决于您的托管环境。我会在我的 API 路由上附加一个随机数以解决此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接