ASP.NET 自定义 404 返回 200 OK 而不是 404 Not Found

发布于 2024-07-09 13:58:37 字数 742 浏览 7 评论 0原文

在尝试为 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 内联代码,我似乎无法使其工作。

After trying to setup my site for Google Webmaster Tools I found that my Custom ASP.NET 404 page was not returning the 404 status code. It displayed the correct custom page and told the browser that everything is OK. This is consider a soft 404 or false 404. Google doesn't like this. So I found many articles on the issue but the solution I want didn't seem to work.

The solution I want to work is adding the following two lines to the code behind Page_Load method of the custom 404 page.

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

This doesn't work. The page still returns 200 OK. I found however that if I hard code the following code into the design code it will work properly.

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

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

 ... Much more code ...

</asp:content>

The page is using a master page. And I am configuring custom error pages in my web.config. I would really rather use the code behind option but I can't seem to make it work without putting a the hack inline code in the design / layout.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

甜柠檬 2024-07-16 13:58:37

解决方案:

事实证明,问题出在母版页的使用上。 我通过在页面生命周期的后期设置状态代码来使其工作,显然母版页的渲染正在重置它,所以我覆盖了渲染方法并在渲染完成后设置它。

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

可以做更多的工作来查明母版页何时设置状态,但我将把它留给您。


原始帖子

我能够让一个测试网络应用程序正常工作,它至少显示了自定义错误页面并返回了 404 状态代码。 我无法告诉你你的应用程序出了什么问题,但我可以告诉你我做了什么:

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

 
    <错误状态代码=“404”重定向=“404.aspx”/> 
   
  

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

公共分部类_04:System.Web.UI.Page 
  { 
      protected void Page_Load(对象发送者,EventArgs e) 
      { 
          响应.StatusCode = 404; 
      } 
  } 
  

就是这样,如果我转到由 Asp.Net 处理且不存在的任何页面扩展,我的 fiddler 日志会清楚地显示 404,这是标题:

HTTP/1.1 404 未找到 
  服务器:微软-IIS/5.1 
  日期:2008 年 12 月 7 日,星期日 06:04:13 GMT 
  X-Powered-By: ASP.NET 
  X-AspNet-版本:2.0.50727 
  缓存控制:私有 
  内容类型:text/html;   字符集=utf-8 
  内容长度: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

Solution:

The problem, it turned out, was the use of the master page. I got it to work by setting the status code later in the pages lifecycle, obviously the rendering of the master page was resetting it, so I overrode the render method and set it after the render was complete.

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

More work could be done to find out exactly when the master page is setting the status, but I'll leave that to you.


Original Post:

I was able to get a test web app to work fine, well it at least displayed the custom error page and returned a 404 status code. I can't tell you what is wrong with your app, but I can tell you what I did:

1) Edited the web.config for custom errors:

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

2) Added a 404.aspx page and set the status code to 404.

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

Thats about it, if I go to any page extension that is processed by Asp.Net and does not exist, my fiddler log clearly shows a 404, here is the header:

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

Now if I go to a page that is not processed by Asp.Net, like a htm file, the custom page does not show and the 404 that is configured by IIS is displayed.

Here is a post that goes into some more details that may be of use to you and your problem, my test does do a redirect to the new page so the url of the requested file is pretty much lost (except its in the query string).

Google 404 and .NET Custom Error Pages

Header Spy Response:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT
隱形的亼 2024-07-16 13:58:37

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

解决方案是添加

Response.TrySkipIisCustomErrors = true;

Before更改 Response.StatusCode。

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

I had a similar problem I want to show a custom page as a 404 (which is ASPX) and it worked fine on localhost but as soon as a remote visitor connected they would get the generic IIS 404.

The solution to this was to add

Response.TrySkipIisCustomErrors = true;

Before changing the Response.StatusCode.

Found via Rick Strahl http://www.west-wind.com/weblog/posts/745738.aspx

帅气尐潴 2024-07-16 13:58:37

尝试调用 Response.End() 跳过渲染...

Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;

Try calling Response.End() to skip rendering...

Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;
东北女汉子 2024-07-16 13:58:37

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

The IIS 7 solution is to just add this to your web.config file:

<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

压抑⊿情绪 2024-07-16 13:58:37

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

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

无论如何,这都将允许页面返回正确的返回代码。

After much testing and troubleshooting it appears that certain hosting providers can interfere with the return code. I was able to get around this by applying a "hack" in the content.

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

This will allow the page to return the correct return code no matter what.

夜声 2024-07-16 13:58:37

我能够通过使用 .NET 3.5 在 asp.net webforms 中使用以下设置来解决这个问题。

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

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

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

此设置确保 CustomErrors 模式设置为打开(稍后我们将需要此设置),并为 error.htm 的 defaultRedirect 提供 all-else-fails 选项。 当我没有特定错误的处理程序,或者存在数据库连接中断的情况时,这会派上用场。

其次,这是全局 asax Error 事件:

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 页面执行“抛出 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,并在标头中写入相应的状态代码。

希望这可以帮助。

I was able to get around this issue by using the following setup in asp.net webforms using .NET 3.5.

The pattern I've implemented bypasses .NET's custom redirect solution in the web.config as I've written my own to handle all scenarios with the correct HTTP status code in the header.

First, the web.config's customErrors section looks like this:

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

This setup ensures that CustomErrors mode is set to on, a setting we'll need later, and provides an all-else-fails option for the defaultRedirect of error.htm. This will come in handy when I don't have a handler for the specific error, or there's something along the lines of a broken database connection.

Second, here's the global asax Error event:

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();
    }
    }

This code is passing off the responsibility of handling the error to another class. If the error isn't handled and CustomErrors is turned on, that means we've got a case where we're on production and somehow an error hasn't been handled. We'll clear it here in order to prevent the user from seeing it, but log it in Elmah so we know what's going on.

The applicationErrorHandler class looks like this:

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;
        }

This class essentially uses the command pattern to locate the appropriate error handler for the type of error that's issued. It's important to use Exception.GetBaseException() at this level, because almost every error will be wrapped in a higher-level exception. For example, doing "throw new System.Exception()" from any aspx page will result in an HttpUnhandledException being received at this level, not a System.Exception.

The "factory" code is simple and looks like this:

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();
    }

In the end, I've got an extensible error handling scheme setup. In each one of the "behaviors" that is defined, I have a custom implementation for the type of error. For example, a Http exception will be inspected for the status code and handled appropriately. A 404 status code will require a Server.Transfer instead of a Request.Redirect, along with the appropriate status code written in the header.

Hope this helps.

漫漫岁月 2024-07-16 13:58:37

您可以使用以下代码:

 Response.TrySkipIisCustomErrors = True
 Response.Status = "404 Not Found"
 Response.AddHeader("Location", "{your-path-to-your-404-page}")

You can use the below code:

 Response.TrySkipIisCustomErrors = True
 Response.Status = "404 Not Found"
 Response.AddHeader("Location", "{your-path-to-your-404-page}")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文