我可以在IIS中定义如何处理“页面未找到/404”错误,也可以在我的应用程序中将其放入自定义错误部分或在代码中处理它。
现在我假设IIS始终首先收到请求,那么它何时会自己处理404,何时会让其通过到我的应用程序?
另外一个问题:IIS是否能够知道asp.net MVC中的请求是否是404错误,因为它可能已经映射到任何路由?
ControllerBuilder.Current.SetControllerFactory(new TestControllerFactory());
并将此类添加到全新的MVC项目中:
public class TestControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
//throw new Exception("Oops!"); // yellow screen of death
throw new System.Web.HttpException(404, "Oops not found!"); // bubbles up to IIS
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
导航到您的项目http://localhost/MvcApplication1/unmapped,并查看当您使用代码404抛出HttpException时发生了什么,与当您抛出常规异常(甚至是具有其他代码的HttpException)时发生了什么。
确保您在IIS下运行项目(而不是VS Dev Server),因为它们处理这些事情的方式不同。
IIS会查看请求的扩展名。如果有一个已注册的模块来处理进来的请求类型,那么它将把请求转发给该模块。
例如,如果您从服务器请求foo.jpg,则IIS内置了一个模块来处理image/jpg内容。如果该模块找不到文件,则返回404。
同样的道理。无论您的MVC处理程序不寻找什么(即:图像),IIS都会以另一种方式处理。
现在我假设IIS总是先收到请求,那么它什么时候处理自己的404错误,什么时候让它通过到我的应用程序?
虽然请求最初由ISS处理,但它会通过到达MVC应用程序。如果找不到文件,则会抛出HttpException,该异常会向IIS返回。如果找到文件,则直接提供服务,绕过路由。true
(默认值为false)时,您需要创建一个路由来处理所有静态内容。但是,正如此处的帖子所建议的那样,根据Steve Sanderson的说法,路由系统将首先检查磁盘上是否存在文件。(请参见相关SO问题,特别是评论部分,以获得更好的澄清)。Global.asax
文件中使用Application_Error()
和Application_EndRequest()
事件,并检查HttpContext.Current.Response
对象,以查看提供内容时的最终响应。
还有一个问题:在asp.net MVC中,如果请求可能或可能没有通过任何路由映射而导致404错误,IIS是否能够知道?
这就是路由配置发挥作用的地方。由于MVC首先会检查文件是否存在,如果存在,则直接提供服务并绕过路由。对于控制器和操作,同样适用。例如,
/SomeController/ActionThatDoesExist
首先被检查以验证它是否为物理文件。显然,这不是一个文件,应用程序将返回404异常。
我认为与此问题相关的第三个方面是MVC和IIS如何协同工作。我指的是“集成模式”和“经典模式”。可以在这里找到一个很棒的解释。
IIS总是处理请求,然后将其转发到MVC应用程序。这基本上决定了如何处理它。
如果磁盘上已经有一个物理文件,则整个路由将被绕过并提供该文件。如果找不到文件,则尝试匹配路由。如果仍然无法解决,则MVC应用程序可能会处理404,否则它会抛出HTTPException,IIS处理404。
我相信即使在Webforms中,404情况在内部也基本相同。唯一的区别是目标始终是物理磁盘,但请求仍然转到ASP.NET Webforms,以防您想自己处理404。
你需要确保在MVC应用程序内执行,就像其他人所说的那样,通常情况下IIS会首先将请求传递到MVC,只有当MVC将404异常传递到足够高的位置时,IIS才会将其返回并应用其决策过程。
关键是:正确处理MVC中的404错误!