C# ASP.NET 自定义 404 返回 200 OK 而不是 404 Not Found
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/347281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET Custom 404 Returning 200 OK Instead of 404 Not Found
提问by Bobby Cannon
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.
在尝试为 Google 网站管理员工具设置我的网站后,我发现我的自定义 ASP.NET 404 页面没有返回 404 状态代码。它显示了正确的自定义页面并告诉浏览器一切正常。这被认为是软 404 或假 404。Google 不喜欢这样。所以我找到了很多关于这个问题的文章,但我想要的解决方案似乎没有用。
The solution I want to work is adding the following two lines to the code behind Page_Load method of the custom 404 page.
我想工作的解决方案是将以下两行添加到自定义 404 页面的 Page_Load 方法后面的代码中。
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.
这不起作用。页面仍然返回 200 OK。然而,我发现如果我将以下代码硬编码到设计代码中,它将正常工作。
<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.config 中配置自定义错误页面。我真的宁愿使用代码隐藏选项,但如果不在设计/布局中放置 hack 内联代码,我似乎无法使其工作。
采纳答案by Ryan Cook
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:
我能够让测试网络应用程序正常工作,它至少显示了自定义错误页面并返回了 404 状态代码。我不能告诉你你的应用程序有什么问题,但我可以告诉你我做了什么:
1) Edited the web.config for custom errors:
1) 针对自定义错误编辑了 web.config:
<customErrors mode="On"> <error statusCode="404" redirect="404.aspx"/> </customErrors>
<customErrors mode="On"> <error statusCode="404" redirect="404.aspx"/> </customErrors>
2) Added a 404.aspx page and set the status code to 404.
2) 添加了 404.aspx 页面并将状态码设置为 404。
public partial class _04 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Response.StatusCode = 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:
就是这样,如果我转到任何由 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
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.
现在,如果我转到一个未由 Asp.Net 处理的页面,例如 htm 文件,则不会显示自定义页面并显示 IIS 配置的 404。
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).
这是一篇文章,其中详细介绍了可能对您和您的问题有用的更多细节,我的测试确实重定向到新页面,因此所请求文件的 url 几乎丢失了(查询字符串中的除外) .
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
回答by Bobby Cannon
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.
这将允许页面无论如何返回正确的返回代码。
回答by gary
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.
我有一个类似的问题,我想将自定义页面显示为 404(即 ASPX),它在本地主机上运行良好,但是一旦远程访问者连接,他们就会获得通用的 IIS 404。
The solution to this was to add
解决这个问题的方法是添加
Response.TrySkipIisCustomErrors = true;
Before changing the Response.StatusCode.
在更改 Response.StatusCode 之前。
Found via Rick Strahl http://www.west-wind.com/weblog/posts/745738.aspx
通过 Rick Strahl 找到http://www.west-wind.com/weblog/posts/745738.aspx
回答by Jason Goemaat
Try calling Response.End() to skip rendering...
尝试调用 Response.End() 跳过渲染...
Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;
回答by Nick D
The IIS 7 solution is to just add this to your web.config file:
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>
回答by letsgetsilly
I was able to get around this issue by using the following setup in asp.net webforms using .NET 3.5.
我能够通过使用 .NET 3.5 在 asp.net webforms 中使用以下设置来解决这个问题。
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.
我实现的模式绕过了 web.config 中 .NET 的自定义重定向解决方案,因为我已经编写了自己的方法来处理标头中包含正确 HTTP 状态代码的所有场景。
First, the web.config's customErrors section looks like this:
首先,web.config 的 customErrors 部分如下所示:
<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.
此设置可确保将 CustomErrors 模式设置为 on,这是我们稍后需要的设置,并为 error.htm 的 defaultRedirect 提供 all-else-fails 选项。当我没有特定错误的处理程序时,这将派上用场,或者有一些与断开的数据库连接相关的东西。
Second, here's the global asax Error event:
其次,这是全局 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();
}
}
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.
此代码将处理错误的责任转移给另一个类。如果错误没有被处理并且 CustomErrors 被打开,这意味着我们有一个案例,我们在生产中并且不知何故没有处理错误。我们将在此处清除它以防止用户看到它,但将它记录在 Elmah 中以便我们知道发生了什么。
The applicationErrorHandler class looks like this:
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;
}
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.
这个类本质上使用命令模式来为发出的错误类型定位适当的错误处理程序。在此级别使用 Exception.GetBaseException() 很重要,因为几乎每个错误都将包含在更高级别的异常中。例如,从任何 aspx 页面执行“throw new System.Exception()”将导致在此级别接收到 HttpUnhandledException,而不是 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.
最后,我有一个可扩展的错误处理方案设置。在定义的每一个“行为”中,我都有一个针对错误类型的自定义实现。例如,将检查 Http 异常以获取状态代码并进行适当处理。404 状态代码将需要 Server.Transfer 而不是 Request.Redirect,以及在标头中写入的适当状态代码。
Hope this helps.
希望这可以帮助。
回答by Rami Zebian
You can use the below code:
您可以使用以下代码:
Response.TrySkipIisCustomErrors = True
Response.Status = "404 Not Found"
Response.AddHeader("Location", "{your-path-to-your-404-page}")