如何返回 404 状态,其中无效参数被传递到我的 ASP.NET MVC 控制器?
Posted
技术标签:
【中文标题】如何返回 404 状态,其中无效参数被传递到我的 ASP.NET MVC 控制器?【英文标题】:How do I return a 404 status where invalid parameters are passed to my ASP.NET MVC controller? 【发布时间】:2012-02-17 09:32:04 【问题描述】:如果将无效参数传递给我的控制器,我想返回 HTTP 状态 404
。例如,如果我有一个看起来像这样的控制器:
public ActionResult GetAccount(int id)
...
如果遇到诸如此类的网址,我想返回404
:
即我想捕获被抛出的ArgumentException
。
我知道我可以使用可为空的类型:
public ActionResult GetAccount(int? id)
if(id == null) throw new HttpException(404, "Not found");
但这很讨厌而且重复。
我希望可以在必要时将其添加到我的控制器中:
[HandleError(View="Error404", ExceptionType = typeof(ArgumentException))]
public class AccountsController : Controller
public ActionResult GetAccount(int id)
...
但这似乎效果不佳。
我看到this post 和this answer 几乎解决了我的问题:
在该答案中,创建了一个抽象的 BaseController,您可以从中派生所有其他控制器:
public abstract class MyController : Controller
#region Http404 handling
protected override void HandleUnknownAction(string actionName)
// If controller is ErrorController dont 'nest' exceptions
if (this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
public ActionResult InvokeHttp404(HttpContextBase httpContext)
IController errorController = ObjectFactory.GetInstance<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(
httpContext, errorRoute));
return new EmptyResult();
#endregion
这非常适合使用404
处理未知操作,但不允许我以404
处理无效数据。
我可以像这样安全地覆盖Controller.OnException(ExceptionContext filterContext)
:
protected override void OnException(ExceptionContext filterContext)
if(filterContext.Exception.GetType() == typeof(ArgumentException))
filterContext.ExceptionHandled = true;
this.InvokeHttp404(filterContext.HttpContext);
else
base.OnException(filterContext);
从表面上看,它似乎可以工作,但我这样做是否会存储任何问题?
这样做在语义上正确吗?
【问题讨论】:
【参考方案1】:最好的方法?动作方法选择器属性!
为了真正避免可以为空的方法参数,我建议您编写一个Action Method Selector 属性,该属性实际上仅在提供id
时才匹配您的操作方法。它不会说没有提供该参数,而是说它无法匹配给定请求的任何操作方法。
我会将此操作选择器称为RequireRouteValuesAttribute
并以这种方式工作:
[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
...
为什么这是解决您问题的最佳解决方案?
如果您查看您的代码,您希望在与名称匹配但参数绑定失败的操作上返回 404(因为未提供或任何其他原因)。可以这么说,您的操作需要特定的操作参数,否则会返回 404。
因此,当添加动作选择器属性时,会添加对动作的要求,因此它必须匹配名称(由 MVC 给出)并且还需要特定的动作参数。每当未提供 id
时,此操作不匹配。如果有另一个匹配的操作不是这里的问题,因为该特定操作将被执行。主要的事情已经完成。操作与无效路由请求不匹配,而是返回 404。
有一个应用代码!
检查my blog post,它实现了您可以开箱即用的这种属性。它完全符合您的要求:如果提供的路由数据没有所有必需的值,它将与您的操作方法不匹配。
【讨论】:
谢谢@jgauffin...MVC 实际上有很多我们甚至不知道的自定义钩子...我知道我不知道很多...;)【参考方案2】:我设法通过在所有路线的末尾添加这条路线来完成这项工作:
routes.MapRoute("CatchAllErrors", "*url",
new controller = "Error", action = "NotFound"
);
注意:首先我关注的是:How can I properly handle 404 in ASP.NET MVC?
【讨论】:
【参考方案3】:免责声明:这并不涵盖所有情况
对于您示例中的 url,返回 404 可以在单行中完成。只需为id
参数添加路由约束即可。
routes.MapRoute(
"Default", // Route name
"controller/action/id", // URL with parameters
new controller = "Home", action = "Index" , // Parameter defaults
new id = @"\d+" // restrict id to be required and numeric
);
仅此而已。现在,任何没有 id
或 id
的匹配 url 都不是数字,自动触发未找到错误(有很多方法可以处理,一种在您的示例中,另一种通过使用自定义 HandleErrorAttribute
等)。您可以在您的操作中使用不可为空的int
参数。
【讨论】:
但是...他可能不需要所有控制器和操作来提供 ID...这只是某些边缘情况的部分解决方案。以上是关于如何返回 404 状态,其中无效参数被传递到我的 ASP.NET MVC 控制器?的主要内容,如果未能解决你的问题,请参考以下文章
预检具有无效的 HTTP 状态代码 404 Jquery AJAX POST