定制“Server Too Busy”错误信息(这是我Copy来的我先声明哦,因为感觉很好的文章)

定制“Server Too Busy”错误信息

     当你访问博客园,出现“Server Error in '/' Application.Runtime Error.”的错误时,你知道这个错误的背后是什么吗? 你也许会想,博客园怎么不设计个定制错误页面?这样的错误页面让访问者不知所措,只能抱怨“服务器出问题了”。当出现这个问题时,我急啊!   真想站到互联网上,拿着大喇叭对大家喊,我刚更新了程序或者修改了web.config的设置,asp.net在进行首次编译,在编译的同时还要处理大量 的请求,忙不过来,只能拒绝请求,实际的错误信息是"Server Too Busy",错误来自HttRuntime的RejectRequestInternal方法。你也许会说用customErrors页面处理一下啊!可 是HttRuntime已经拒绝了这个请求,重定向到defaultRedirect定制错误页面,还是被拒绝,结果就出现“Server Error in '/' Application.Runtime Error.”错误。这个问题困扰我很长时间,当更新程序(或者修改web.config的设置、应用程序池回收、IIS重启)时,就会出现这个问题,尤 其是访问高峰期,要几分种才能恢复正常,郁闷!  要是在这时显示一个友好的错误显示页面,那该多好啊!今天晚上更新程序时,又遇到这个问题。我再次下决心要解决这个问题。
     要解决问题,首先要分析出为什么会出现问题。既然是HttRuntime抛出的异常,那就从HttRuntime下手。怎么下手呢?用强大的 Reflector工具,微软这点做的不错,很多.NET类库都可以通过Reflector工具查看源代码。通过分析HttRuntime的源代码,我找 到了问题的原因,这里我简单地描述了一下:

     当请求被发送到ASP.NET Worker Process时,先是由HttpRuntime的ProcessRequest方法处理,在ProcessRequest方法中,先从请求队列 (RequestQueue)中获取有效的请求(GetRequestToExecute),如果有有效的请求,就调用 HttpRuntime.ProcessRequestNow进行进一步的处理。而"Server Too Busy"的异常就是在GetRequestToExecute中产生的,GetRequestToExecute方法代码如下:

internal  HttpWorkerRequest GetRequestToExecute(HttpWorkerRequest wr)
{
      
int  num1;
      
int  num2;
      ThreadPool.GetAvailableThreads(
out  num1,  out  num2);
      
int  num3  =  (num2  >  num1)  ?  num1 : num2;
      
if  ((num3  <   this ._minExternFreeThreads)  ||  ( this ._count  !=   0 ))
      
{
            
bool  flag1  =  RequestQueue.IsLocal(wr);
            
if  ((flag1  &&  (num3  >=   this ._minLocalFreeThreads))  &&  ( this ._count  ==   0 ))
            
{
                  
return  wr;
            }

            
if  ( this ._count  >=   this ._queueLimit)
            
{
                  HttpRuntime.RejectRequestNow(wr);
                  
return   null ;
            }

            
this .QueueRequest(wr, flag1);
            
if  (num3  >=   this ._minExternFreeThreads)
            
{
                  wr 
=   this .DequeueRequest( false );
                  
return  wr;
            }

            
if  (num3  >=   this ._minLocalFreeThreads)
            
{
                  wr 
=   this .DequeueRequest( true );
                  
return  wr;
            }

            wr 
=   null ;
            
this .ScheduleMoreWorkIfNeeded();
      }

      
return  wr;
}

     我们分析一下上面的代码:程序先从管理线程中获取有效线程的数目(num3)。如是num3大于minFreeThreads(该值对应于 machine.config或者web.config中HttpRuntime段的minFreeThreads属性,即使执行新请求所需要的最小空闲 线程数)并且请求队列中没有请求,则直接处理当前请求;如果num3小于minFreeThreads或者当前请求队列不为空("Server Too Busy"的请求就是这种情况), 从上面的代码中我们会发现当请求队列(RequestQueue)中请求数大于
_queueLimit(该 值对应于machine.config或者web.config中HttpRuntime段的appRequestQueueLimit属性) 时,HttpRumtime就会拒绝当前请求(RejectRequestNow),RejectRequestNow中直接调用 RejectRequestInternal(HttpWorkerRequest wr), 在RejectRequestInternal中抛出了"Server_too_busy", 抛出异常后,立即捕获异常,你说怪吧,为什么不直接处理?为什么要在抛出异常后又捕获?有点多此一举?可能设计者还有其他考虑吧,比如为了代码更好的重 用。

try
      
{
            
throw   new  HttpException( 0x1f7 , HttpRuntime.FormatResourceString( " Server_too_busy " ));
      }

      
catch  (Exception exception1)
      
{
            context1.Response.InitResponseWriter();
            
this .FinishRequest(wr, context1, exception1);
            
return ;
      }

      接着就是异常的处理,向客户端浏览器显示异常信息,调用FinishRequest, 在Finish中调用context.Response.ReportRuntimeError(e, true)显示异常信息,ReportRuntimeError会根据web.config中的CustomErrors设置决定是否重定向到 defaultRedirect。
     当你设置CustomErrors的defaultRedirect来定制处理异常信息时,如果遇到"Server_too_busy"就麻烦了,重定向 到错误处理页面后,又被HttpRuntime拒绝,拒绝后又被重定向到defaultRedirect页面,HttpRuntime《———》 HttpRuntime.....,似乎进入了一种恶性循环。原来问题有这么严重,写文章之前我还没想到,写到这我才发现。这样不停的来回,CPU岂不累 死,当CPU累的不行时,就随便抛出一个其他异常:),也就是“Server Error in '/' Application.Runtime Error.”,这个异常我没找到在哪抛出的。难道在首次编译时,CPU占用很高与这个也有关系。我更新博客园服务器上的程序时,要几分钟才能恢复正常, 而这时CPU基本是满负荷工作,难道也是这个问题引起,我想明天在访问高峰期测试一下就能得到证实。这似乎是设计者的一个疏忽,正确的做法应该是对 于"Server_too_busy"异常,不管用户是否设置了defaultRedirect, 都不应该去重定向到defaultRedirect,而是直接向客户端发送异常信息,这是一个很特殊的情况,设计者在设计时可能没考虑到。
     在 写文章之前,我并没有发觉这个问题如此严重。但我想到了一个另类的解决方法,既然发生"Server_too_busy"时,HttpRuntime不会 处理任何请求,那该Web应用程序中再怎么处理也是无济于事的, 我们从其他地方找突破口,发生"Server_too_busy"异常时,重定向到 defaultRedirect会带来严重的问题,但却可以利用这一点把问题化解为解决方法,这个解决方法就是:将defaultRedirect设置为 另外一个网站的地址,既然这个网站拒绝处理请求,那我把请求转给另外一个网站,总可以吧,由另外一个网站来显示友好的错误信息,这样不仅解决了定制 “Server Too Busy”错误信息的问题,而且可以减少对主网站的请求,让主网站有更多的时间处理当前的任务。比如:博客园现在就建立了一个 sorry.cnblogs.com的站点,将defaultRedirect设置为这个站点。这个方法另类吧! 
     有了这个方法,我们以后就不怕"Server_too_busy"了,可以轻松更新程序、修改web.config, 只要将defaultRedirect的页面设计得让大家觉得等几分钟也不难受就行了。比如:放一段美妙的音乐、笑话、搞笑图片、***,当然过份的网站 也许会放广告。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值