CustomErrors在设置redirectMode =“ResponseRewrite”时不起作用
在旧网站中,我通过添加redirectMode="ResponseRewrite"
(3.5 SP1中的新增function)来改变CustomErrors的工作方式:
<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite"> <error statusCode="404" redirect="404.aspx" /> </customErrors>
问题是:它向我展示了通用的错误页面(当你不设置customErrors
时候会得到一个错误页面),如果我删除了redirectMode="ResponseRewrite"
部分,它就可以正常工作。
我确定3.5 SP1安装在服务器上,因为我在同一服务器上托pipe的其他站点上使用相同的设置。
有任何想法吗?
对于任何尝试在MVC应用程序中执行此操作的人来说, ResponseRewrite
使用Server.Transfer
在幕后都很重要。 因此, defaultRedirect
必须对应于文件系统上的合法文件。 显然, Server.Transfer
与MVC路由不兼容,因此,如果错误页面由控制器操作提供, Server.Transfer
将查找/ Error / Whatever,在文件系统上找不到它,并返回一个通用404错误页面!
对我来说完美的唯一方法是closures自定义错误,并通过web.configreplaceiis的错误页面。 它发送正确的状态码与响应,并有没有通过mvc的好处。
这是代码
-
closures自定义错误
<customErrors mode="Off" />
-
更换错误页面
<httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404" subStatusCode="-1" /> <remove statusCode="500" subStatusCode="-1" /> <error statusCode="404" path="Error404.html" responseMode="File" /> <error statusCode="500" path="Error.html" responseMode="File" /> </httpErrors>
注意。 如果url是直接链接到文件,则使用responsemode="file"
info: http : //tipila.com/tips/use-custom-error-pages-aspnet-mvc
发生了什么是IIS是错误状态代码,并提出自己的错误页面,而不是你的。 为了解决你需要在你的错误页面的页面后面的代码中设置这个,以防止IIS这样做:
Response.TrySkipIisCustomErrors = true;
这只适用于IIS7或更高版本,对于早期版本的IIS,您需要使用错误页面设置。
我知道这个问题有点老,但我想我应该指出,它不需要是一个静态文件来获得这个工作。
我遇到了一个类似的事情,这只是在你的Error.aspx中find这个错误的问题,在我们的情况下,这是因为使用的masterpage依赖于一段会话数据,并且当设置ResponseRewrite时,session不可用我们的Error.aspx页面。
我还没有制定出会议是否由于我们特定的应用程序configuration或ASP.net的“devise”部分。
由于对Server.Transfer
的依赖,似乎ResponseRewrite
的内部实现与MVC不兼容。
这对我来说似乎是一个明显的function漏洞,所以我决定使用HTTP模块重新实现此function,以便它正常工作 。 下面的解决scheme允许您通过redirect到任何有效的MVC路由(包括物理文件)来处理错误,就像正常情况一样。
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite"> <error statusCode="404" redirect="404.aspx" /> <error statusCode="500" redirect="~/MVCErrorPage" /> </customErrors>
这已经在以下平台上进行了testing。
- 集成pipe道模式下的MVC4(IIS Express 8)
- 经典模式下的MVC4(VS开发服务器,Cassini)
- 经典模式下的MVC4(IIS6)
namespace Foo.Bar.Modules { /// <summary> /// Enables support for CustomErrors ResponseRewrite mode in MVC. /// </summary> public class ErrorHandler : IHttpModule { private HttpContext HttpContext { get { return HttpContext.Current; } } private CustomErrorsSection CustomErrors { get; set; } public void Init(HttpApplication application) { System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~"); CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors"); application.EndRequest += Application_EndRequest; } protected void Application_EndRequest(object sender, EventArgs e) { // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it) if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) { int statusCode = HttpContext.Response.StatusCode; // if this request has thrown an exception then find the real status code Exception exception = HttpContext.Error; if (exception != null) { // set default error status code for application exceptions statusCode = (int)HttpStatusCode.InternalServerError; } HttpException httpException = exception as HttpException; if (httpException != null) { statusCode = httpException.GetHttpCode(); } if ((HttpStatusCode)statusCode != HttpStatusCode.OK) { Dictionary<int, string> errorPaths = new Dictionary<int, string>(); foreach (CustomError error in CustomErrors.Errors) { errorPaths.Add(error.StatusCode, error.Redirect); } // find a custom error path for this status code if (errorPaths.Keys.Contains(statusCode)) { string url = errorPaths[statusCode]; // avoid circular redirects if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) { HttpContext.Response.Clear(); HttpContext.Response.TrySkipIisCustomErrors = true; HttpContext.Server.ClearError(); // do the redirect here if (HttpRuntime.UsingIntegratedPipeline) { HttpContext.Server.TransferRequest(url, true); } else { HttpContext.RewritePath(url, false); IHttpHandler httpHandler = new MvcHttpHandler(); httpHandler.ProcessRequest(HttpContext); } // return the original status code to the client // (this won't work in integrated pipleline mode) HttpContext.Response.StatusCode = statusCode; } } } } } public void Dispose() { } } }
用法
将其作为最终的HTTP模块包含在web.config中
<system.web> <httpModules> <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" /> </httpModules> </system.web> <!-- IIS7+ --> <system.webServer> <modules> <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" /> </modules> </system.webServer>
我发现问题在Error.aspx。 仍然无法find导致问题的error.aspx中的实际错误。
将页面更改为静态html文件解决了这个问题。
我在aspx中build立了一个错误页面,将查询传递给ASP.NET MVC控制器。 您可以将查询重写为此aspx页面,并将查询传输到您的自定义控制器。
protected void Page_Load(object sender, EventArgs e) { //Get status code var queryStatusCode = Request.QueryString.Get("code"); int statusCode; if (!int.TryParse(queryStatusCode, out statusCode)) { var lastError = Server.GetLastError(); HttpException ex = lastError as HttpException; statusCode = ex == null ? 500 : ex.GetHttpCode(); } Response.StatusCode = statusCode; // Execute a route RouteData routeData = new RouteData(); string controllerName = Request.QueryString.Get("controller") ?? "Errors"; routeData.Values.Add("controller", controllerName); routeData.Values.Add("action", Request.QueryString.Get("action") ?? "Index"); var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData); IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName); controller.Execute(requestContext); }
在这里find更多细节: https : //stackoverflow.com/a/27354140/143503
在我的特定情况下,我的错误页面有一个主页,有一个用户控件试图使用会话。 如果Session不可用,您将得到一个HttpException:“只有当enableSessionState设置为true时,才能在configuration文件或Page指令中使用会话状态。 最简单的解决方法是切换到静态html,第二个最简单的解决方法是使用一个更简单的错误页面,最难的解决方法是令人难以置信的确保您的错误页面不会在任何地方做出假设(例如,会话不会抛出exception,例如)和不可能出错。
我发现如果你使用redirectMode =“ResponseRewrite”,那么你需要在web.config文件的重写区域添加一些东西。 问题是当你的网站坏了! 你不能重写URL,因为你的站点无法调用处理重写的“virtual.aspx”。