仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1043|回复: 13
打印 上一主题 下一主题

[学习教程] ASP.NET网站制作之Response.Redirect引发的“没法在发送HTTP标头以后举行重定向”仓酷云 ...

[复制链接]
只想知道 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-18 11:14:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
我之所以想学。NET,是因为一直觉的BILLGATES好厉害,希望有一天能去微软,虽然现在还距离遥远,呵呵:)博客背景切换至i.cnblogs.com以后,在日记中发明大批的“没法在发送HTTP标头以后举行重定向”(CannotredirectafterHTTPheadershavebeensent)的毛病信息。
反省代码发明成绩是由上面的代码触发的:
  1. IHttpHandlerIHttpHandlerFactory.GetHandler(HttpContextcontext,stringrequestType,stringurl,stringpathTranslated){context.Response.Redirect("http://i.cnblogs.com/"+context.Request.RawUrl.Substring(context.Request.RawUrl.LastIndexOf("/")+1));//后续也有context.Response.Redirect代码//...returnPageParser.GetCompiledPageInstance(newurl,path,context);}
复制代码

“没法在发送HTTP标头以后举行重定向”成绩来历于Response.Redirect以后,又举行了Response.Redirect。
办理办法很复杂:在Response.Redirect以后当即前往。
  1. IHttpHandlerIHttpHandlerFactory.GetHandler(HttpContextcontext,stringrequestType,stringurl,stringpathTranslated){context.Response.Redirect("http://i.cnblogs.com/"+context.Request.RawUrl.Substring(context.Request.RawUrl.LastIndexOf("/")+1));returnnull;//...}
复制代码

为何之前没有加returnnull呢?由于之前一向觉得Response.Redirect会停止以后哀求,不会实行Response.Redirect以后的代码。
如今严酷的实际申明了不完整是如许的,那成绩面前的原形是甚么?让我们来一探求竟。
因为微软公然了.NETFramework的源代码,如今无需再看Reflactor出来的代码,能够间接下载源代码用VisualStudio举行检察。
.NETFramework源代码下载链接:http://referencesource.microsoft.com/download.html(相干旧事:微软开放了.NET4.5.1的源代码)
用VisualStudio翻开DotNetReferenceSourceSourcendp.sln,搜刮HttpResponse.cs,找到Response.Redirect的完成代码:
  1. publicvoidRedirect(Stringurl){Redirect(url,true,false);}
复制代码
实践挪用的是internalvoidRedirect(Stringurl,boolendResponse,boolpermanent),传给endResponse的值切实其实是true啊,为何前面的代码还会实行?
进一步检察internalvoidRedirect()的完成代码(省略了有关代码):
  1. internalvoidRedirect(Stringurl,boolendResponse,boolpermanent){//...Pagepage=_context.HandlerasPage;if((page!=null)&&page.IsCallback){//抛非常}//...url处置Clear();//Clearsallheadersandcontentoutputfromthebufferstream.//...this.StatusCode=permanent?301:302;//举行重定向操纵//..._isRequestBeingRedirected=true;varredirectingHandler=Redirecting;if(redirectingHandler!=null){redirectingHandler(this,EventArgs.Empty);}if(endResponse)End();//停止以后哀求}
复制代码

从下面的代码能够看出,我们要找的原形在End()办法中,持续看HttpResponse.End()的完成代码:
  1. publicvoidEnd(){if(_context.IsInCancellablePeriod){AbortCurrentThread();}else{//whencannotabortexecution,flushandsupressfurtheroutput_endRequiresObservation=true;if(!_flushing){//ignoreReponse.Endwhileflushing(inOnPreSendHeaders)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(),以是不会碰到这个成绩。
而我们如今的场景恰好是由于_context.IsInCancellablePeriod的值为false,为何会是false呢?
进一步看一下_context.IsInCancellablePeriod的完成:
  1. privateint_timeoutState;//0=non-cancelable,1=cancelable,-1=canceledinternalboolIsInCancellablePeriod{get{return(Volatile.Read(ref_timeoutState)==1);}}
复制代码
依据下面的代码,触发这个成绩的前提是_timeoutState的值要末是0,要末是-1,依据我们的实践情形,应当是0=non-cancelable。
再来看看我们的实践使用场景,我们是在完成IHttpHandlerFactory接口的GetHandler办法中举行Response.Redirect操纵的,也就是说在这个阶段_timeoutState的值还没被设置(默许值就是0)。为了考证这个设法,持续看一下_timeoutState在哪一个阶段设值的。
Shift+F12找到一切援用_timeoutState的中央,在HttpConext中发明了设置_timeoutState的办法BeginCancellablePeriod,完成代码以下:
  1. internalvoidBeginCancellablePeriod(){//ItcouldbecausedbyanexceptioninOnThreadStartif(Volatile.Read(ref_timeoutStartTimeUtcTicks)==-1){SetStartTime();}Volatile.Write(ref_timeoutState,1);}
复制代码

然后再Shift+F12找到了在HttpApplication.ExecuteStep()中挪用了BeginCancellablePeriod():
  1. internalExceptionExecuteStep(IExecutionStepstep,refboolcompletedSynchronously){//..if(step.IsCancellable){_context.BeginCancellablePeriod();//requestcanbecancelledfromthispoint}//..}
复制代码

从下面的代码能够看出,当step.IsCancellable为true时,会挪用BeginCancellablePeriod(),就不会呈现这个成绩。
而我们用到的IHttpHandlerFactory.GetHandler()地点的IExecutionStep的完成大概将IsCancellable设置为了false。
那IHttpHandlerFactory.GetHandler()是在哪一个IExecutionStep的完成中挪用的呢?
在园子里木宛城主的一篇写得十分棒的博文(ASP.NET那点不为人知的事)中找到了谜底——MapHandlerExecutionStep:
当实行到MapHandlerExecutionStep时会实行以下代码猎取终极实行哀求:context.Handler=this._application.MapHttpHandler()。HttpApplication对象的MapHttpHandler办法将依据设置文件分离哀求范例和URL以挪用响应的IHttpHandlerFactory来猎取HttpHandler对象。
我们再回到.NETFramework的源代码中看一看MapHandlerExecutionStep的完成:
  1. //executionstep--mapHTTPhandler(usedtobeaseparatemodule)internalclassMapHandlerExecutionStep:IExecutionStep{privateHttpApplication_application;internalMapHandlerExecutionStep(HttpApplicationapp){_application=app;}voidIExecutionStep.Execute(){//...}boolIExecutionStep.CompletedSynchronously{get{returntrue;}}boolIExecutionStep.IsCancellable{get{returnfalse;}}}
复制代码

看到有无?IExecutionStep.IsCancellable前往的值是false。
到此,内情毕露,水落石出!
请看年夜屏幕——
因为MapHandlerExecutionStep(挪用IHttpHandlerFactory.GetHandler()的中央)前往的IsCancellable的值是false,因而在HttpApplication.ExecuteStep()实行时没有挪用_context.BeginCancellablePeriod()——也就是没有把_timeoutState设置为1,_context.IsInCancellablePeriod的值就是false。从而形成在Response.Redirect中举行Response.End()时没有实行AbortCurrentThread()(一般情形下城市实行这个)。因而代码持续实行,前面又来一次Response.Redirect,终极激发了——“没法在发送HTTP标头以后举行重定向”(CannotredirectafterHTTPheadershavebeensent)。
听03很多师兄说主讲老师杭城方讲课很差就连旁听也没有去了)
透明 该用户已被删除
沙发
发表于 2015-1-20 18:21:36 | 只看该作者
弱类型造成潜在的出错可能:尽管弱数据类型的编程语言使用起来回方便一些,但相对于它所造成的出错几率是远远得不偿失的。
兰色精灵 该用户已被删除
板凳
发表于 2015-1-21 09:44:21 | 只看该作者
代码逻辑混乱,难于管理:由于ASP是脚本语言混合html编程,所以你很难看清代码的逻辑关系,并且随着程序的复杂性增加,使得代码的管理十分困难,甚至超出一个程序员所能达到的管理能力,从而造成出错或这样那样的问题。
分手快乐 该用户已被删除
地板
发表于 2015-1-21 11:18:14 | 只看该作者
业务逻辑代码都不必做任何改动;继承性和多态性使得代码的可重用性大大提高,你可以通过继承已有的对象最大限度保护你以前的投资。并且C#和C++、Java一样提供了完善的调试/纠错体系。
admin 该用户已被删除
5#
发表于 2015-1-23 18:15:26 | 只看该作者
由于JSP/Servlet都是基于Java的,所以它们也有Java语言的最大优点——平台无关性,也就是所谓的“一次编写,随处运行(WORA–WriteOnce,RunAnywhere)”。除了这个优点,JSP/Servlet的效率以及安全性也是相当惊人的。
爱飞 该用户已被删除
6#
发表于 2015-1-24 12:48:33 | 只看该作者
由于CGI程序每响应一个客户就会打开一个新的进程,所以,当有多个用户同时进行CGI请求的时候,服务器就会打开多个进程,这样就加重了服务器的负担,使服务器的执行效率变得越来越低下。
飘飘悠悠 该用户已被删除
7#
发表于 2015-1-30 19:55:26 | 只看该作者
代码的可重用性差:由于是面向结构的编程方式,并且混合html,所以可能页面原型修改一点,整个程序都需要修改,更别提代码重用了。
再现理想 该用户已被删除
8#
发表于 2015-2-5 22:52:59 | 只看该作者
主流网站开发语言之CGI:CGI就是公共网关接口(CommonGatewayInterface)的缩写。它是最早被用来建立动态网站的后台技术。这种技术可以使用各种语言来编写后台程序,例如C,C++,Java,Pascal等。
第二个灵魂 该用户已被删除
9#
发表于 2015-2-12 23:07:38 | 只看该作者
可以看作是VC和Java的混合体吧,尽管MS自己讲C#内核中更多的象VC,但实际上我还是认为它和Java更象一些吧。首先它是面向对象的编程语言,而不是一种脚本,所以它具有面向对象编程语言的一切特性。
灵魂腐蚀 该用户已被删除
10#
发表于 2015-2-23 19:23:02 | 只看该作者
我觉得什么语言,精通就好,你要做的就是比其他80%的人都厉害,你就能得到只有20%的人才能得到的高薪。
蒙在股里 该用户已被删除
11#
发表于 2015-3-1 13:49:57 | 只看该作者
主流网站开发语言之CGI:CGI就是公共网关接口(CommonGatewayInterface)的缩写。它是最早被用来建立动态网站的后台技术。这种技术可以使用各种语言来编写后台程序,例如C,C++,Java,Pascal等。
冷月葬花魂 该用户已被删除
12#
发表于 2015-3-6 16:51:06 | 只看该作者
ASP.Net和ASP的最大区别在于编程思维的转换,而不仅仅在于功能的增强。ASP使用VBS/JS这样的脚本语言混合html来编程,而那些脚本语言属于弱类型、面向结构的编程语言,而非面向对象。
不帅 该用户已被删除
13#
发表于 2015-3-12 11:37:19 | 只看该作者
有一丝可惜的是,这个系列太强了,Java阵营的朋友根本就是哑口无言...争论之火瞬间被浇灭,这不是我想这么早就看到的,但是值了。
若相依 该用户已被删除
14#
发表于 2015-3-19 21:29:19 | 只看该作者
目前在微软的.net战略中新推出的ASP.net借鉴了Java技术的优点,使用CSharp(C#)语言作为ASP.net的推荐语言,同时改进了以前ASP的安全性差等缺点。但是,使用ASP/ASP.net仍有一定的局限性,因为从某种角度来说它们只能在微软的WindowsNT/2000/XP+IIS的服务器平台上良好运行(虽然像ChilliSoft提供了在UNIX/Linux上运行ASP的解决方案.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-24 00:39

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表