charminglee

Cannot redirect after HTTP headers have been sent.

   这个错误前后遇到了几次,由于没做记录导致以前的解决方法又要重新来过一遍,而且,说句心里话,也一直没有真正找到理想的解决方法。不过,重要的是能够解决,因此,在这里还是记录一下,如果有更好的,不妨UPDATE一下,呵呵。
        产生错误的原因:
        在Response.Redirect(...);前面使用了Response.Cache.SetCacheability(HttpCacheability.NoCache );
        解决思路:
  1。BufferOutput=true,ClearHeaders,ClearContent,Clear都试过了,完全不起作用。
  2。在SERVER端使用JAVASCRIPT的脚本方法实在是不喜欢。
  3。经过一番考证(特别是下面的第二点),感觉象是IE的问题,但不知道怎么修复,于是重新安装了一下IE,一切OK,感觉很不错(虽然隐隐地觉得肯定有不需要重装IE,只需更改IE的一些设置就能实现的办法在,但以后在说了)。虽然麻烦,但三者中,更偏爱这一种。
 对自己很有帮助的两篇文章不得不引用一下。
    一。
 Chandra Sekhar has suggested a good solution; ClearHeaders or ClearContent. Just make sure BufferOutput is true (it is by default). A Javascript redirect is good but you don't know if it is disabled on the client (and with many recent security issues it may be).

Alternatively, write your output to a string variable then use an if...else statement for calling either Response.Write or Response.Redirect.
 
    Response.ClearHeaders and Response.ClearContents will only work if Response.BufferOutput is true (which is by default). In fact, if BufferOutput is set to false, the Response object will send data to the browser immediately on every call.

Does your code set the BufferOutput field to false?
eg. Response.BufferOutput = false;

    If so, you will not be able to call Write and then call Redirect in the same code block.

    If the compression utility is doing it, then you will need to hack the above change out of it.

    However, the problem does not occur with Server.Transfer().

    二。http://dotnetjini.jigneshdesai.com/dotnet-whidbey/ShowArticle.aspx?ID=6

Response.Redirect, Server.Tranfer and Server.Execute SANGRAM

As the title suggest some times I really feel a ASP programmer while migrating to ASP.NET has to really deal with these three options since these where not there in classic ASP until IIS5 and ASP 3.0. and their cosmetic change in ASP.NET, thus there are some issues also which one needs to understand before he uses them or rather I should say misuse them. one of the simplest example of its misuse is recorded here http://dotnetjini.jigneshdesai.com/Blogs/default.aspx?MNo=10&YNo=2004 


Response.Redirect(): when u use this method the IIS server does not redirect the user to requested page infact IIS sends the following HTTP header to the browser.:

            HTTP 1.0 302 Object Move
            Location URL

making the browser automatically request a new page. Since the redirection goes through a round-trip to the browser, it generates an additional request and increased bandwidth usage. Another point to remember here for classic ASP programmers is that buffering is turned on by default in IIS5 so if there is any output thrown before redirect statement will not cause any exception like in ASP, the exception message as seen below.

            System.Web.HttpException: Cannot redirect after HTTP headers have been sent.

Also Response.Buffer is outdated instead use Response.BufferOutput for any buffering activity.

Limitations:

  1. It forcing you to cancel all output from the first page
  2. You also lose the contents of the Request collection.
  3. Transactions of both pages gets isolated

Server.Transfer(): The server simply transfers the context to another page. When you use Server.Transfer, the destination .ASPx script has access to the same set of intrinsic objects. Since you can use Transfer to call aspx1 which in turn can call aspx2 which in turn can call aspx1 again, so be careful as it may accidentally create any infinite loops, try to avoid circular references. 

Server.Transfer is also useful in error handling procedures. In IIS 5.0, the ASPError object is called when an error is generated. The Server.GetLastError method returns an ASPError object describing the error condition that occurred. If this method is called after an automatic Server.Transfer, it will provide information about what caused the error.

Plus Points:

  1. The current transaction flows to the second page
  2. You can share page context information between pages.

Limitations:

  1. Server.Transfer is limited to the current machine; you cannot transfer requests to another machine.
  2. Because Server.Transfer is executed on the server, user's browser does not know about the transfer, so the browser's history is not updated Therefore, if the user refreshes the page, unexpected results can occur.
  3. You cannot use Server.Transfer to redirect to an .asmx page.
  4. You cannot use Server.Transfer to redirect to an classic .asp page (since ISAPI extension cannot call another ISAPI extension )
  5. The page transferred to should be another Web Forms page (.aspx page) in the same application.

The intresting part is that Server.Transfer method also has a second parameter"preserveForm". If you set this to True, using a statement such as Server.Transfer("WebForm2.aspx", True), the existing query string and any form variables will be available to the page you are transferring to. For example, if your WebForm1.aspx has a TextBox control called TextBox1 and a querystring ID and you transferred to WebForm2.aspx with the preserveForm parameter set to True, you'd be able to retrieve the value of the original page TextBox control by referencing Request.Form("TextBox1") and Request.QueryString("ID") respectively.

Server.Trasfer seems good if there are pages like wizard-style input forms split over multiple pages, but I don't prefer this way, I generally use multiple panel objects in single form,  due to its simple programming approach and then play around with panel's visible property to display different forms in each postback.

We have some issues in certain cases when preserveForm is set to true. You'll find this documented at http://support.microsoft.com/default.aspx?id=kb;en-us;Q316920.

Server.Execute(): The way I look at Server.Execute is its basically an alternative to server-side includes. This method will process another .ASPX page as part of the current .ASPX page. This provides a new way to encapsulate your code and can provide u a true way of conditional #includes. By employing the Server.Execute method, you can develop a library of .aspx files that you can call as needed. This method is analogous to a procedure call in VBScript.

Limitations:

  1. The page transferred to should be another Web Forms page (.aspx page) in the same application, else you will receive an exception "Invalid path for child request '......'. A virtual path is expected."

The best part is you can receive the output of child executing page in a variable, this will allow you flexibility to choose in which section of the screen the output should be rendered. e.g:

                Dim writer As New System.IO.StringWriter
                Server.Execute("Test2.aspx", writer)
                Literal1.Text = writer.ToString()

The trouble starts when classic ASP programmer does not use right overloaded version of above method at appropriate place. Remember when you was Response.Redirect or Server.Transfer it internally calls Response.End, the original file terminates execution and ThreadAbort Exception is raised. so if you are within an try catch block the exception is always catched.

Try
If TextBox1.Text.Equals("jigs") Then
    'Do login update in database
        Response.Redirect("Page2.aspx")
Else
        Response.Redirect("Page3.aspx")
End If
Catch ex As Exception
        'if any errors
        Response.Redirect("CommonError.aspx?id=" + ex.Message)
End Try

The Response.End method ends the page execution and shifts the execution to the Application_EndRequest event (found in global.asax) in the application's event pipeline. The line of code that follows Response.End / Response.Redirect is not executed. To avoid such above mistakes you should avoid handling generic exceptions and always catch specific errors or avoid redirect methods in try catch block or if required as seen above, catch Threading.ThreadAbortException and do nothing.

Try
    targetURL = "somepage.aspx"

Catch ex As Exception
    Session("errormesage") = ex.message
    targetURL = "errorpage.aspx"
Finally
' clean up
End Try
Response.Redirect(targetURL)

The alternative approach is pass 2nd parameter as false in Response.Redirect("Page2.aspx", FALSE ). this will not halt page execution and response.end is not called and hence no exception is raised. because 2nd parameter suppress the internal call to Response.End. An another alternative approach while terminating .aspx page is call the HttpContext.Current.ApplicationInstance.CompleteRequest() method. If you use above mention workaround, the code that follows Response.Redirect is executed.


Response.Redirect has yet another issue since there is difference between IIS4 and IIS5 behavior related to encoded characters, you should read ..

 Summary:
Server.Transfer and Server.Execute create a better application flow control mechanism for the ASP framework. Server.Transfer also facilitates efficient handling of errors. While they won't replace Response.Redirect for all your redirection needs.

if you have any queries/concerns or have any additional information do use post it here.

posted on 2006-03-27 09:16  charming  阅读(2073)  评论(0)    收藏  举报

导航