Response.Redirect引起的“无法在发送HTTP标头之后进行重定向”

博客后台切换至i.cnblogs.com之后,在日志中发现大量的“无法在发送HTTP标头之后进行重定向”(Cannot redirect after HTTP headers have been sent)的错误信息。

检查代码发现问题是由下面的代码触发的:

IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
    context.Response.Redirect("http://i.cnblogs.com/" +
        context.Request.RawUrl.Substring(context.Request.RawUrl.LastIndexOf("/") + 1));

    //后续也有context.Response.Redirect代码
    //...
    return PageParser.GetCompiledPageInstance(newurl, path, context);
}

“无法在发送HTTP标头之后进行重定向”问题来源于Response.Redirect之后,又进行了Response.Redirect。

解决方法很简单:在Response.Redirect之后立即返回。

IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
    context.Response.Redirect("http://i.cnblogs.com/" +
        context.Request.RawUrl.Substring(context.Request.RawUrl.LastIndexOf("/") + 1));
    return null;
    //...
}

为什么之前没有加return null呢?因为以前一直以为Response.Redirect会结束当前请求,不会执行Response.Redirect之后的代码。

现在残酷的现实说明了不完全是这样的,那问题背后的真相是什么?让我们来一探究竟。

由于微软公开了.NET Framework的源代码,现在无需再看Reflactor出来的代码,可以直接下载源代码用Visual Studio进行查看。

.NET Framework源代码下载链接:http://referencesource.microsoft.com/download.html (相关新闻:微软开放了.NET 4.5.1的源代码)

用Visual Studio打开DotNetReferenceSource\Source\ndp.sln,搜索HttpResponse.cs,找到Response.Redirect的实现代码:

public void Redirect(String url)
{
    Redirect(url, true, false);
}

实际调用的是internal void Redirect(String url, bool endResponse, bool permanent) ,传给endResponse的值的确是true啊,为什么后面的代码还会执行?

进一步查看internal void Redirect()的实现代码(省略了无关代码):

internal void Redirect(String url, bool endResponse, bool permanent)
{
    //...

    Page page = _context.Handler as Page;
    if ((page != null) && page.IsCallback) {
        //抛异常
    }

    // ... url处理

    Clear(); //Clears all headers and content output from the buffer stream.

    //...
    this.StatusCode = permanent ? 301 : 302; //进行重定向操作
    //...
    _isRequestBeingRedirected = true; 

    var redirectingHandler = Redirecting;
    if (redirectingHandler != null) {
        redirectingHandler(this, EventArgs.Empty);
    }

    if (endResponse)
        End(); //结束当前请求
}

从上面的代码可以看出,我们要找的真相在End()方法中,继续看HttpResponse.End()的实现代码:

public void End() {
    if (_context.IsInCancellablePeriod) {
        AbortCurrentThread();
    }
    else {
        // when cannot abort execution, flush and supress further output
        _endRequiresObservation = true;

        if (!_flushing) { // ignore Reponse.End while flushing (in OnPreSendHeaders)
            Flush();
            _ended = true;

            if (_context.ApplicationInstance != null) {
                _context.ApplicationInstance.CompleteRequest();
            }
        }
    }
}

注意啦!真相浮现了!

以前一直以为的Response.Redirect会结束当前请求,就是上面的AbortCurrentThread()情况,如果将Response.Redirect放在try...catch中就会捕捉到ThreadAbortException异常。

通常情况下,我们在WebForms的Page或MVC的Controller中进行Redirect,_context.IsInCancellablePeriod的值为true,执行的是AbortCurrentThread(),所以不会遇到这个问题。

更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/aspx/

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索源代码
, string
, redirect
, context
, 代码
, response
, 重定向redirect参数mvc
Request.RawUrl
java 重定向 redirect、js redirect 重定向、重定向redirect、html redirect 重定向、两次重定向redirect,以便于您获取更多的相关知识。

时间: 2024-11-01 08:46:26

Response.Redirect引起的“无法在发送HTTP标头之后进行重定向”的相关文章

Server.Transfer,Response.Redirect的区别

redirect|response|server|区别 Server.Transfer(ASP 3.0 以上) 和 Response.Redirect 在以前的 ASP 中就存在了,Page.Navigate 是 ASP.NET Beta 1 提供的新功能,它们之间的区别在于: 1.Server.Transfer - 用于把处理的控制权从一个页面转移到另一个页面,在转移的过程中,没有离开服务器,内部控件(如:request, session 等)的保存的信息不变,因此,你能从页面 A 跳到页面

Response.redirect实现页面重定向

redirect|response|页面 用 Redirect 方法可将浏览器重定向到另一个 URL,而不是将内容发送给用户.例如,如果您想确认用户是否已从主页进入了您的应用程序,以便能收到一个客户 ID,则可以检验他们是否有客户 ID 号:如果没有,就可以将其重定向到主页.以下就是具体例子:<%If Session("CustomerID") = 0 Then Response.Redirect "homepage.asp" End If%> 除非缓冲

response.redirect和Server.Transfer的区别详解

redirect|response|server|区别|详解 一般会使用response.redirect这条语句进行地址转向,ASP3.0以后提供了一种新的方法给我们,这种方法更加高效.让我们先来看看response.redirect和Server.Transfer分别是如何Run的! response.redirect其实上是当服务器碰到这条语句时发送一条指令(包含新的地址)给浏览器,然后让浏览器去发送http请求,请求response.redirect后面的那个新的http地址,流程如下:

Server.Transfer,Response.Redirect 和 Page.Navigate

Server.Transfer(ASP 3.0 以上) 和 Response.Redirect 在以前的 ASP 中就存在了,Page.Navigate 是 ASP.NET Beta 1 提供的新功能,它们之间的区别在于: 1.Server.Transfer - 用于把处理的控制权从一个页面转移到另一个页面,在转移的过程中,没有离开服务器,内部控件(如:request, session 等)的保存的信息不变,因此,你能从页面 A 跳到页面 B 而不会丢失页面 A 中收集的用户提交信息.此外,在转

Server.Transfer,Response.Redirect 和 Page.Navigate 的区别

redirect|response|server|区别 Server.Transfer(ASP 3.0 以上) 和 Response.Redirect 在以前的 ASP 中就存在了,Page.Navigate 是 ASP.NET Beta 1 提供的新功能,它们之间的区别在于: 1.Server.Transfer - 用于把处理的控制权从一个页面转移到另一个页面,在转移的过程中,没有离开服务器,内部控件(如:request, session 等)的保存的信息不变,因此,你能从页面 A 跳到页面

Response.write后马上运行Response.redirect,Response.write没反应

  我们时常想达到这样的效果: Response.Write("<script>alert("您离线时间过长,请重新登陆!");</script>"); Response.Redirect("Login.aspx"); 我们希望先提示信息,然后再跳转页面.但这样做的结果是:直接跳转,没有提示信息. 这是为什么呢?     Response.Redirect方法之后,这个页面的内容根本就不会被发送到客户端,而是直接在服务器端

asp.net 页面转向 Response.Redirect, Server.Transfer, Server.Execute的区别_实用技巧

Response.Redirect 简单地发送一条消息到浏览器,告诉浏览器定位到另一个页面.你可以使用下面的代码将用户引导到另一个页面: Response.Redirect("WebForm2.aspx") 或者 Response.Redirect("http://www.cnnas.com/") Server.Transfer 也是通过一条语句将用户引导到另一页面,比如:Server.Transfer("WebForm2.aspx").不过,这

让Response.Redirect页面重定向更有效率

用 Redirect 方法可将浏览器重定向到另一个 URL,而不是将内容发送给用户. 这里有一篇文章介绍使用Redirect<Using Response.Redirect Effectively> ,文章详细的讨论了Response.Redirect ,给出了一段代码: public static class HttpResponseExtensions { public static void RedirectUser(this HttpResponse response, string

asp.net 页面转向 Response.Redirect, Server.Transfer, Server.Execute的区别

Response.Redirect 简单地发送一条消息到浏览器,告诉浏览器定位到另一个页面.你可以使用下面的代码将用户引导到另一个页面: Response.Redirect("WebForm2.aspx") 或者 Response.Redirect("http://www.cnnas.com/") Server.Transfer 也是通过一条语句将用户引导到另一页面,比如:Server.Transfer("WebForm2.aspx").不过,这