Server.TransferRequest() 和 HTTP 状态码

7

我不得不实现一个自定义的HttpModule来处理Sharepoint中的404错误。

它监听PreSendRequestContent事件,并查找404状态码。如果找到一个,它会执行TransferRequest。

void App_PreSendRequestContent(object sender, EventArgs e)
{
    HttpResponse res = App.Response;
    HttpRequest req = App.Request;

    if (res.StatusCode == 404 && !req.Url.AbsolutePath.Equals(PageNotFoundUrl, StringComparison.InvariantCultureIgnoreCase))
    {
        App.Server.TransferRequest(PageNotFoundUrl);
    }
}

这很好用,但我在 Fiddler 中发现页面显示的是 200 状态码,尽管原始请求是 404。这对搜索引擎来说不太好。 TransferRequest 是否会出现这种情况?我能否保持 404 状态码?或者,使用传统的 Server.Transfer 是否更好?
更新:
我在 SharePoint 环境之外尝试过,Server.TransferRequest 请求确实会给出一个 200 状态码,移除了 404。由于管道的限制,Server.Transfer 无法工作。
更新2:感谢下面的答案,我已经添加了以下内容:
void App_PostRequestHandlerExecute(object sender, EventArgs e)
{
    HttpResponse res = App.Response;
    HttpRequest req = App.Request;

    if (req.Url.AbsolutePath.Equals(PageNotFoundUrl, StringComparison.InvariantCultureIgnoreCase))
    {
        res.StatusCode = 404;
    }
}

你的 web.config 长什么样子才能让这个工作?对我来说,改变 Response.StatusCode 会使 IIS7 放弃整个响应并返回处理错误,使我所有自定义错误处理代码都无用。 - Asbjørn Ulsberg
@asbjornu - 除了添加httpModule之外,我没有进行任何web.config更改。 - ScottE
很奇怪。每当我设置 Response.StatusCode 时,IIS7就会接管整个响应并呈现自己的自定义错误处理内容。 - Asbjørn Ulsberg
你在使用SharePoint吗?SharePoint有许多模块可以跳入管道,因此它与普通的.NET应用程序不同。 - ScottE
我没有使用SharePoint。 - Asbjørn Ulsberg
@asbjornu - 这个问题和评论可能对你没有帮助。 - ScottE
2个回答

2

Server.TransferRequest 不会改变状态码,它将请求的控制权传递给另一个页面而不告诉客户端。您可以在 Page_Load 事件中手动设置自定义 404 页面的状态码:

protected void Page_Load(object sender, System.EventArgs e)
{
    Response.StatusCode         = 404;
    Response.StatusDescription  = "Not Found";
}

这是有道理的。不幸的是,在SharePoint中,这意味着部署一个发出此状态代码的Web部件...但除此之外它完全正常工作。 - ScottE
此外,我认为你在第一段中不正确——请自行尝试。在页面上设置404状态码,然后执行Server.TransferRequest()函数——你会看到404转成请求转移到的页面返回的任何状态码。顺便说一句,当我说“看到”时,我并不是指两个头部都存在,只是测试开/关将证明这一点。 - ScottE
如果您在Server.TransferRequest的目标页面中设置状态代码,它就可以工作。这是我为我的网站所做的。 - David

2

好的,TransferRequest() 触发了一个新请求,这意味着一个新的响应。由于 PageNotFoundUrl 指向的资源确实存在,客户端将接收到合法的 200 OK 状态头。

你可能需要编写一个 HTTP 处理程序(或在 Global.asax 中处理事件),以便在提供 PageNotFoundUrl 时强制状态头为 404 Not Found


这也有意义,尤其是因为我已经放置了一个httpmodule。在管道的哪个位置应该检查这个? - ScottE
@ScottE,PostRequestHandlerExecute应该是合适的。 - Frédéric Hamidi
完美,我喜欢它,谢谢。问题已更新以包括此解决方案。 - ScottE
在IIS7中,我无法更改状态码。如果我这样做,IIS将接管响应并呈现其自己的HTTP正文,而不管我在自定义错误处理中呈现了什么。 - Asbjørn Ulsberg
1
@asbjornu:Response.TrySkipIisCustomErrors = true; - bang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接