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

Posted

技术标签:

【中文标题】设置 redirectMode="ResponseRewrite" 时,CustomErrors 不起作用【英文标题】:CustomErrors does not work when setting redirectMode="ResponseRewrite" 【发布时间】:2010-10-21 09:04:59 【问题描述】:

在旧站点中,我通过添加 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,因为我在同一服务器上托管的其他站点上使用相同的设置。

有什么想法吗?

【问题讨论】:

【参考方案1】:

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

【讨论】:

我注意到 Web 表单和路由也存在问题,请在此处查看我的问题 ***.com/questions/7269103/… 允许 ResponseRewrite 使用 MVC 路由存在 CodePlex 问题,请投票:aspnet.codeplex.com/workitem/9034 @PussInBoots,这是一个存档链接web.archive.org/web/20131201222548/http://aspnet.codeplex.com/…【参考方案2】:

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

这是代码

    关闭自定义错误

    <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"

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

【讨论】:

查看meta.stackexchange.com/a/22189/147333 了解列表中的代码格式:) 我把自己逼疯了,试图为我的应用程序找到处理错误的“正确”方法,这就是解决方案。我仍然需要处理全局中的一些错误,但这没关系,因为我希望记录这些错误。发生这种情况时,我正在执行 Server.Transfer 到 aspx 错误页面。这个解决方案最重要的部分是用户永远不知道我的处理程序被命名为什么,并且永远不会被带到他们没有请求的 URL。 这个解决方案远非完美,它将取代AJAX和API错误响应***.com/questions/24465261/… 我设置了 existingResponse="Auto" 导致各种问题,因为它与 404 但不是 500 错误一起使用。谢谢!如果您想删除所有以前的 httpErrors,我发现您可以使用 而不是单独的 我还发现我无法将 500 错误传递给控制器​​并像我所做的那样设置 responseMode=ExecuteURL对于有效的 404 错误。【参考方案3】:

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

Response.TrySkipIisCustomErrors = true;

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

【讨论】:

谢谢 - 如果您需要使用 .aspx 页面作为默认重定向,这就是解决方案。 感谢您告诉我有关 TrySkipIisCustomErrors 的信息。我必须切换回 ResponseRedirect,因为我们必须坚持使用 IIS 6... 我在这个答案 ***.com/a/21271085/222748 中添加了更多关于 TrySkipIisCustomErrors 的信息【参考方案4】:

由于对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(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>

【讨论】:

感谢您的解决方案。我已经将代码放到 global.asax 但状态仍然是 200。为了解决集成管道的问题,我们需要更早地设置状态。因此,我能够将其放入 404 页面操作中: [AllowAnonymous] public ActionResult NotFound() Response.StatusCode = 404;返回视图(“未找到”); 我一直很高兴地使用这种方法,但最近发现它会干扰 IIS 应用程序初始化。还没有机会深入研究它,但是当通过 web.config 加载错误处理程序时,它似乎优先于初始化过程。因此,当尝试将remapManagedRequestsTo 属性与skipManagedModules="true" 结合使用时,在重新映射页面加载之前可能会出现明显延迟。我通过loading the module via app initialization 解决了这个问题。 您应该考虑将其作为 Nuget 包发布,这样您就可以获得更多的荣誉,而不是我们所有人都将您的代码复制粘贴到我们自己的命名空间中。【参考方案5】:

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

我遇到了类似的事情,这只是在您的 Error.aspx 中找到该错误的问题,在我们的例子中,这是因为使用的母版页依赖于一段会话数据,并且在设置 ResponseRewrite 时会话是不适用于我们的 Error.aspx 页面。

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

【讨论】:

是的,你是对的。就我而言,我找不到错误,所以我使用静态 HTML 来确保安全。【参考方案6】:

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

将页面更改为静态 html 文件即可解决问题。

【讨论】:

【参考方案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://***.com/a/27354140/143503

【讨论】:

我将这里提供的解决方案与***.com/a/5536676/2310818 结合起来处理各种错误,无论是由于未知路由、未知控制器、未知操作、控制器操作返回的 HttpNotFound() 结果,以及控制器抛出的 HttpException。我实现了所有这些,同时根据错误代码的类型实现了正确的状态代码(404、500)。 @ParthShah,它单独使用此解决方案,但可能对返回错误的方式有一些限制(我猜是抛出异常而不是返回结果,但我真的不记得了)。使用 ASP MVC/Web API 和 IIS 处理错误是一件很痛苦的事情,很高兴你设法让它工作;)【参考方案8】:

根据@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>

注意:由于ASP.net application中的RouteConfig.cs,我删除了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>

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:

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

【讨论】:

以上是关于设置 redirectMode="ResponseRewrite" 时,CustomErrors 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用AlermManager设置闹钟

vue-router 根据权限动态设置路由 theme.js" as it exceeds the max of "500KB".

怎么给android 设置边框

app.config 如何配置显示详细的错误信息,比如哪一行出错了,它会显示?

layui富文本框怎么设置默认值?

android怎么用代码给checkbox设置style-CSDN论坛