设置redirectMode =“ResponseRewrite”时,CustomErrors不起作用

时间:2009-04-23 14:01:51

标签: asp.net iis-6 custom-errors redirectmode

在旧网站中,我通过添加redirectMode="ResponseRewrite"(3.5 SP1中的新功能)来更改CustomErrors的工作方式:

<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
</customErrors> 

问题是:它向我显示了一般错误页面(当您未设置customErrors时获得的页面。如果我删除了redirectMode="ResponseRewrite"部分,它可以正常工作。

我确定服务器中安装了3.5 SP1,因为我在同一服务器上托管的其他网站上使用相同的设置。

有什么想法吗?

10 个答案:

答案 0 :(得分:99)

重要的是要注意在ResponseRewrite幕后使用Server.Transfer的MVC应用程序中尝试执行此操作的任何人。因此,defaultRedirect必须对应于文件系统上的合法文件。显然,Server.Transfer与MVC路由不兼容,因此,如果您的错误页面由控制器操作提供,Server.Transfer将查找/ Error / Whatever,而不是在文件系统上找到它,并返回一个通用的404错误页面!

答案 1 :(得分:46)

对我来说唯一合适的方法是关闭自定义错误并通过web.config替换iis的错误页面。它使用响应发送正确的状态代码,并且具有不通过mvc的好处。

这是代码

  1. 关闭自定义错误

    <customErrors mode="Off" />
    
  2. 替换错误页面

    <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>
    
  3. 请注意。如果网址是文件的直接链接,请使用responsemode="file"

    info:http://tipila.com/tips/use-custom-error-pages-aspnet-mvc

答案 2 :(得分:20)

正在发生的事情是IIS正在查看错误状态代码并显示它自己的错误页面而不是您的错误页面。要解决此问题,您需要在错误页面的代码隐藏页面中进行设置,以防止IIS执行此操作:

Response.TrySkipIisCustomErrors = true;

这只适用于IIS7或更高版本,对于早期版本的IIS,您需要使用错误页面设置。

答案 3 :(得分:14)

由于依赖Server.TransferResponseRewrite的内部实现似乎与MVC不兼容。

这对我来说似乎是一个明显的功能漏洞,因此我决定使用HTTP模块重新实现此功能,以便它可以正常工作。下面的解决方案允许您通过重定向到任何有效的MVC路由(包括物理文件)来处理错误,就像您正常做的那样。

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
    <error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>

已在以下平台上测试过;

  • 集成管道模式下的MVC4(IIS Express 8)
  • 经典模式下的MVC4(VS开发服务器,卡西尼)
  • 经典模式下的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() {

        }


    }

}

<强>用法

将其作为web.config

中的最终HTTP模块包含在内
  <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>

答案 4 :(得分:9)

我知道这个问题有点陈旧,但我想我应该指出它不需要是一个静态文件才能使这个工作。

我遇到了类似的事情,这只是在你的Error.aspx中发现错误的问题,在我们的例子中是因为使用的主页依赖于一段会话数据,并且当设置了ResponseRewrite时,会话是我们的Error.aspx页面无法使用。

我还没有确定会话的不可用性是由于我们的特定应用配置还是ASP.net的“设计”部分。

答案 5 :(得分:1)

我发现问题出在Error.aspx中。仍然无法找到导致问题的error.aspx中的实际错误。

将页面更改为静态html文件解决了这个问题。

答案 6 :(得分:1)

我在aspx中构建了一个错误页面,用于将查询传输到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);
}

在此处查找更多详情:https://stackoverflow.com/a/27354140/143503

答案 7 :(得分:0)

在我的特定情况下,我的错误页面有一个母版页,其中有一个试图使用Session的用户控件。如果Session不可用,则会出现HttpException:“只有在配置文件或Page指令中将enableSessionState设置为true时才能使用会话状态。” 最简单的修复方法是切换到静态html,第二个最简单的修复方法是使用更简单的错误页面,最难的修复方法就是确保你的错误页面不会在任何地方做出任何假设(例如,Session不会抛出异常),不可能出错。

答案 8 :(得分:0)

我发现如果你使用redirectMode =“ResponseRewrite”,那么你需要在web.config文件的重写区域中添加一些东西。问题是你的网站坏了!您无法进行网址重写,因为您的网站无法调用处理重写的“virtual.aspx”!

答案 9 :(得分:0)

根据@Amila的帖子以及该帖子的确认和完成,我有同样的问题,我在谷歌上挖了很多东西,但没有机会找到正确的答案。问题是当您使用ASP.Net Web Application时,无论它是MVC,还是无法使用旧的Webform project方法来实现自定义错误。
如果您使用的是ASP.Net Web Application(是否为MVC),则为以下选项:

在我的场景中,我只想为特定的404错误定义一个自定义错误,另一个错误定义为与404错误相同:


Senario1 :您的自定义页面是一个简单的HTML文件,位于root中:

<configuration>
   <system.web>
      <customErrors mode="Off" />
   </system.web>
   <system.webServer>
       <httpErrors errorMode="Custom" existingResponse="Replace">
           <remove statusCode="404" subStatusCode="-1" />
           <error statusCode="404" path="ErrorPage.html" responseMode="File" />
       </httpErrors>
   </system.webServer>
</configuration>



Senario2 :您的自定义页面是一个aspx页面,并放置在root中:

<configuration>
   <system.web>
      <customErrors mode="Off" />
   </system.web>
   <system.webServer>
       <httpErrors errorMode="Custom" existingResponse="Replace">
           <remove statusCode="404" subStatusCode="-1" />
           <error statusCode="404" path="ErrorPage" responseMode="Redirect" />
       </httpErrors>
   </system.webServer>
</configuration>

注意:由于RouteConfig.cs中有ASP.net application,我删除了aspx扩展名,您可以根据需要使用ErrorPage.aspx,这是可选的。


Senario3 :您的自定义页面是一个aspx页面,并放置在[ex: Page folder in The root (~/Page/ErrorPage.aspx)]中:
我注意到这里的提示是您不应使用~/ 到根地址;所以我只添加没有~/标记的地址:

<configuration>
   <system.web>
      <customErrors mode="Off" />
   </system.web>
   <system.webServer>
       <httpErrors errorMode="Custom" existingResponse="Replace">
           <remove statusCode="404" subStatusCode="-1" />
           <error statusCode="404" path="Page/ErrorPage" responseMode="Redirect" />
       </httpErrors>
   </system.webServer>
</configuration>