代码之家  ›  专栏  ›  技术社区  ›  Eduardo Molteni

设置RedirectMode=“ResponseRewrite”时,customErrors不工作

  •  70
  • Eduardo Molteni  · 技术社区  · 15 年前

    在一个旧网站中,我通过添加 redirectMode="ResponseRewrite" (3.5 SP1中的新增功能):

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

    问题是:它向我显示了一般性错误页面(当你不设置时得到的页面) customErrors . 如果我删除 RedirectMode=“响应写入” 部分,它工作得很好。

    我确信服务器中安装了3.5SP1,因为我在同一服务器上承载的其他站点上使用相同的设置。

    有什么想法吗?

    9 回复  |  直到 7 年前
        1
  •  97
  •   Mike Atlas    14 年前

    对于在MVC应用程序中尝试执行此操作的任何人来说,需要注意的是 ResponseRewrite 使用 Server.Transfer 在幕后。因此, defaultRedirect 必须对应于文件系统上的合法文件。显然地, 服务器传输 与MVC路由不兼容,因此,如果错误页由控制器操作提供服务, 服务器传输 将查找/error/无论什么,而不是在文件系统中找到它,并返回一个一般的404错误页!

        2
  •  43
  •   JT.    11 年前

    对于我来说,唯一有效的方法是关闭自定义错误并通过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>
      

    注意事项。使用 responsemode="file" 如果URL是指向文件的直接链接

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

        3
  •  20
  •   Michael    15 年前

    现在的情况是,IIS正在获取错误状态代码,并显示自己的错误页面,而不是您的错误页面。要解决此问题,需要在错误页的代码页中设置此项,以防止IIS这样做:

    Response.TrySkipIisCustomErrors = true;
    

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

        4
  •  12
  •   Red Taz    10 年前

    由于依赖 Server.Transfer 似乎在内部实施 ResponseRewrite 与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(与开发服务器、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() {
    
            }
    
    
        }
    
    }
    

    用法

    将其作为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>
    
        5
  •  9
  •   Chris    15 年前

    我知道这个问题有点老了,但我想我应该指出,它不需要是一个静态文件就可以工作。

    我遇到了一个类似的问题,这只是在你的error.aspx中发现错误的问题,在我们的例子中,这是因为正在使用的masterpage依赖于一段会话数据,当responseRewrite被设置时,会话对error.aspx页不可用。

    我还没有弄清楚会话的不可用性是由于我们的特定应用程序配置还是ASP.NET的“按设计”部分。

        6
  •  1
  •   Eduardo Molteni    15 年前

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

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

        7
  •  1
  •   Community CDub    7 年前

    我在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

        8
  •  0
  •   David Eison    14 年前

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

        9
  •  0
  •   Colin Wiseman    14 年前

    我发现,如果您使用redirectmode=“responserewrite”,那么您需要在web.config文件的重写区域添加一些内容。问题在于你的网站何时被破坏!你不能重写URL,因为你的网站不能调用处理你的重写的“virtual.aspx”!