ASP.NET自定义404返回200 OK,而不是找不到404


80

在尝试为Google网站站长工具设置我的网站后,我发现我的“自定义ASP.NET 404”页面未返回404状态代码。它显示了正确的自定义页面,并告诉浏览器一切正常。这被视为软404或错误404。Google不喜欢这样。因此,我找到了很多有关该问题的文章,但是我想要的解决方案似乎没有用。

我要工作的解决方案是将以下两行添加到自定义404页面的Page_Load方法后面的代码中。

Response.Status = "404 Not Found";
Response.StatusCode = 404;

这行不通。该页面仍然返回200 OK。但是我发现,如果我将以下代码硬编码到设计代码中,它将可以正常工作。

<asp:Content ID="ContentMain" ContentPlaceHolderID="ContentPlaceHolderMaster" runat="server">

<%
    Response.Status = "404 Not Found";
    Response.StatusCode = 404;
%>

 ... Much more code ...

</asp:content>

该页面正在使用母版页。我在web.config中配置自定义错误页面。我真的很想使用选项背后的代码,但是如果不在设计/布局中加入hack内联代码,我似乎无法使其工作。


浏览器状态如何?我使用用于Firefox的插件标头间谍。
鲍比·坎农

标头间谍响应:未找到HTTP / 1.1 404日期:2008年
赖安·库克

您正在使用母版页吗?也许就是这样。我将尝试使用不使用母版页的页面...
Bobby Cannon

不,我不是,但是我也可以进行快速检查,我会尝试一下。
瑞安·库克

是的,就是这样!母版页导致200 OK
Ryan Cook

Answers:


72

解:

事实证明,问题出在母版页的使用上。我可以通过在页面生命周期的稍后阶段设置状态代码来使其正常工作,很明显,母版页面的渲染正在重置它,因此我覆盖了render方法,并在渲染完成后进行设置。

protected override void Render(HtmlTextWriter writer)
{
    base.Render(writer);
    Response.StatusCode = 404;
}

可以做更多的工作来确切地知道母版页何时设置状态,但是我将留给您。


原始帖子:

我能够获得一个测试Web应用程序,可以正常运行,它至少显示了自定义错误页面并返回了404状态代码。我无法告诉您您的应用程序有什么问题,但可以告诉您我做了什么:

1)编辑了web.config中的自定义错误:

<customErrors mode="On">
  <error statusCode="404" redirect="404.aspx"/>
</customErrors>

2)添加了404.aspx页面并将状态代码设置为404。

public partial class _04 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.StatusCode = 404;
    }
}

就是这样,如果我转到由Asp.Net处理并且不存在的任何页面扩展名,我的提琴手日志中都会清楚显示404,这是标头:

HTTP/1.1 404 Not Found
Server: Microsoft-IIS/5.1
Date: Sun, 07 Dec 2008 06:04:13 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 533

现在,如果我转到不被Asp.Net处理的页面(如htm文件),则不会显示自定义页面,并显示由IIS配置的404。

这是一则帖子,其中详细介绍了一些可能对您和您的问题有用的信息,我的测试确实将重定向到新页面,因此所请求文件的url几乎丢失了(查询字符串中的内容除外) 。

Google 404和.NET自定义错误页面

标头间谍响应:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT

4
标头间谍是附加组件Firefox标头间谍
Kiquenet 2015年

静态.html自定义错误页面如何使用?
ebyrob

28

我有一个类似的问题,我想将自定义页面显示为404(ASPX),它在localhost上运行良好,但是一旦远程访问者连接,他们就会获得通用的IIS 404。

解决方案是添加

Response.TrySkipIisCustomErrors = true;

更改Response.StatusCode之前。

通过Rick Strahl找到http://www.west-wind.com/weblog/posts/745738.aspx


12

IIS 7解决方案是将其添加到您的web.config文件中:

<system.webServer>
  <httpErrors existingResponse="Replace">
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" prefixLanguageFilePath="" path="404.htm" responseMode="File" />
    <error statusCode="500" prefixLanguageFilePath="" path="500.htm" responseMode="File" />
  </httpErrors>
</system.webServer>

http://forums.asp.net/t/1563128.aspx/1


3
为我工作!唯一适用于此的解决方案,可能是由于您所注明的版本所致...注意:此解决方案只能使用静态.htm文件。
squarecandy2012年


9

经过大量测试和故障排除后,似乎某些托管服务提供商可能会干扰返回代码。通过在内容中应用“ hack”,我能够解决此问题。

<%
// This code is required for host that do special 404 handling...
Response.Status = "404 Not Found";
Response.StatusCode = 404;
%>

无论如何,这将使页面返回正确的返回码。


1

我可以通过使用.NET 3.5在asp.net Webforms中使用以下设置来解决此问题。

我实现的模式绕过了web.config中.NET的自定义重定向解决方案,因为我编写了自己的模式以使用标头中的正确HTTP状态代码来处理所有情况。

首先,web.config的customErrors部分如下所示:

<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />

此设置可确保将CustomErrors模式设置为on,这是我们稍后需要的设置,并为error.htm的defaultRedirect提供了all-else-fails选项。当我没有针对特定错误的处理程序,或者数据库连接断开时出现某些问题时,这将派上用场。

其次,这是全局asax错误事件:

protected void Application_Error(object sender, EventArgs e)
    {
       HandleError();
    }

    private void HandleError()
    {
        var exception = Server.GetLastError();
        if (exception == null) return;

        var baseException = exception.GetBaseException();

        bool errorHandled = _applicationErrorHandler.HandleError(baseException);
        if (!errorHandled) return;


        var lastError = Server.GetLastError();
    if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
        Server.ClearError();
    }
    }

此代码将处理错误的责任转移给另一个类。如果未处理错误且CustomErrors处于打开状态,则意味着我们遇到了正在生产中的情况,并且某种程度上未处理错误。为了防止用户看到它,我们将在此处清除它,但是将其记录在Elmah中,以便我们了解发生了什么。

applicationErrorHandler类如下所示:

public bool HandleError(Exception exception)
        {
            if (exception == null) return false;

            var baseException = exception.GetBaseException();

            Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);

            if (!HttpContext.Current.IsCustomErrorEnabled) return false;

            try
            {

                var behavior = _responseBehaviorFactory.GetBehavior(exception);
                if (behavior != null)
                {
                    behavior.ExecuteRedirect();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
            }
            return false;
        }

此类实际上使用命令模式来为发出的错误类型找到合适的错误处理程序。在此级别使用Exception.GetBaseException()很重要,因为几乎每个错误都将包装在更高级别的异常中。例如,从任何aspx页面执行“ throw new System.Exception()”将导致在此级别接收HttpUnhandledException,而不是System.Exception。

“工厂”代码很简单,如下所示:

public ResponseBehaviorFactory()
    {
        _behaviors = new Dictionary<Type, Func<IResponseBehavior>>
                        {
                            {typeof(StoreException), () => new Found302StoreResponseBehavior()},
                            {typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
                            {typeof(HttpException), () => new HttpExceptionResponseBehavior()},
                            {typeof(Exception), () => new Found302DefaultResponseBehavior()}
                        };
    }

    public IResponseBehavior GetBehavior(Exception exception)
    {                                                                               
        if (exception == null) throw new ArgumentNullException("exception");

        Func<IResponseBehavior> behavior;
        bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);

        //default value here:
        if (!tryGetValue)
            _behaviors.TryGetValue(typeof(Exception), out behavior);

        if (behavior == null)
            Elmah.ErrorSignal.FromCurrentContext().Raise(
                new Exception(
                    "Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
                    exception));
        return behavior();
    }

最后,我有一个可扩展的错误处理方案设置。在定义的每个“行为”中,我都有一个针对错误类型的自定义实现。例如,将检查Http异常的状态代码并进行适当处理。404状态代码将需要Server.Transfer而不是Request.Redirect,以及在标头中写入的相应状态代码。

希望这可以帮助。


0

您可以使用以下代码:

 Response.TrySkipIisCustomErrors = True
 Response.Status = "404 Not Found"
 Response.AddHeader("Location", "{your-path-to-your-404-page}")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.