今天解决了一位朋友使用 Anthem.NET 遇到的问题。他的代码在 Windows XP 的开发机器上反应正常,而部署到 2003 Server 的服务器上就提示 "BADRESPONSE".
这个问题产生的原因是,Anthem 在客户端 js 中调用服务器时,会返回一个表示 js 对象的文本,在得到后,通过 eval 方式将这个对象还原。其中包括了服务器需要返回给客户端的各种信息,比如脚本,更新的 html, ViewState 等。
如果这个 eval 出错,则会提示 'BADRESPONSE'.
通过查看页面输出可以看到:
JavaScript:
如何分析错误呢,很明显,我们只要看看 responseText 是什么,就会知道这个文本为什么不能被 eval 估算了。
因为 Anthem_GetResult 是由 Anthem 的 dll 动态输出的,我们需要修改这个函数的定义。
方法是在 </body> 前面,加一段代码来修改这个函数的定义即可:
JavaScript:
在正常情况下,alert 提示的信息如下:
看上去有点乱,我们把它还原为正常的 js 代码,实际上是这样一个对象:
JavaScript:
其中 controls 是需要更新 innerHTML 的客户端控件集合,以及要更新的源代码。
Anthem.NET 修改了常见默认控件的 Render 方法,使控件输出的 HTML 外围多了一个容器控件. 而每次回调后,都会通过这个人为添加的容器来更新其中的控件 HTML 输出。
看如下 HTML:
HTML:
这段代码中,span 便是 LinkButton 的容器。
上述返回对象中的 script 属性,是在服务器端设定的,需要在返回后执行的脚本代码的集合。
服务器端可以通过下列语句来添加脚本:
C#:
以上分析的是 Anthem 在正常工作的情况下输出的对象,那么错误时会输出什么内容呢?下面是一个例子:
我们看到其中有乱码信息,可以判断 Anthem 是遇到了编码问题导致输出错误了。
于是重新设定页面的编码,解决了这个问题。
分析一下 Anthem 的实现,可以看到 Anthem 在发送请求时的设定代码:
JavaScript:
其默认请求编码是 utf-8 的。
而其输出编码,则可以通过 web.config 来定制。方法如下:
这个办法是我通过分析 Anthem 的源码发现的,奇怪的是在其文档中好像没有发现相关的说明。
相关代码如下:
Manager.cs (C#):
小结一下使用 Anthem.NET 碰到脚本问题的查错方法:
首先定位到 Anthem.NET 产生的某个具体函数,然后,可以在页面的 </body> 前插入代码来改写该函数,在其中加入调试语句来定位问题。
当然,以上所说的是在部署服务器这种受限的环境下(通常没有开发环境)排错的方法,如果能够直接调试页面的 JavaScript 就更方便了。比如可以用 Visual Studio, 或者 MSE.exe 等工具来调试。
这个问题产生的原因是,Anthem 在客户端 js 中调用服务器时,会返回一个表示 js 对象的文本,在得到后,通过 eval 方式将这个对象还原。其中包括了服务器需要返回给客户端的各种信息,比如脚本,更新的 html, ViewState 等。
如果这个 eval 出错,则会提示 'BADRESPONSE'.
通过查看页面输出可以看到:
JavaScript:
function
Anthem_GetResult(x) {
var result = { " value " : null , " error " : null };
var responseText = x.responseText;
try {
result = eval( " ( " + responseText + " ) " );
} catch (e) {
if (responseText.length == 0 ) {
result.error = " NORESPONSE " ;
} else {
result.error = " BADRESPONSE " ;
result.responseText = responseText;
}
}
return result;
}
var result = { " value " : null , " error " : null };
var responseText = x.responseText;
try {
result = eval( " ( " + responseText + " ) " );
} catch (e) {
if (responseText.length == 0 ) {
result.error = " NORESPONSE " ;
} else {
result.error = " BADRESPONSE " ;
result.responseText = responseText;
}
}
return result;
}
如何分析错误呢,很明显,我们只要看看 responseText 是什么,就会知道这个文本为什么不能被 eval 估算了。
因为 Anthem_GetResult 是由 Anthem 的 dll 动态输出的,我们需要修改这个函数的定义。
方法是在 </body> 前面,加一段代码来修改这个函数的定义即可:
JavaScript:
function
Anthem_GetResult(x) {
var result = { " value " : null , " error " : null };
var responseText = x.responseText;
alert(responseText);
try {
result = eval( " ( " + responseText + " ) " );
} catch (e) {
if (responseText.length == 0 ) {
result.error = " NORESPONSE " ;
} else {
result.error = " BADRESPONSE " ;
result.responseText = responseText;
}
}
return result;
}
var result = { " value " : null , " error " : null };
var responseText = x.responseText;
alert(responseText);
try {
result = eval( " ( " + responseText + " ) " );
} catch (e) {
if (responseText.length == 0 ) {
result.error = " NORESPONSE " ;
} else {
result.error = " BADRESPONSE " ;
result.responseText = responseText;
}
}
return result;
}
在正常情况下,alert 提示的信息如下:
---------------------------
Windows Internet Explorer
---------------------------
{ " value " : null , " error " : null , " viewState " : " /wEPDwUKMTQ4NzkxOTExMGRkLHCpj5eYh3HaWUC4wwfnI1kE8sI= " , " eventValidation " : " /wEWAgKw5r+UAwLM9PumD2DQQ4RF4lRuD5Qz+1A07BOdo0rx " , " controls " :{ " LinkButton1 " : " <a οnclick=/ " Anthem_FireCallBackEvent( this ,event,'LinkButton1','', true ,'','','', true , null , null , null , true , true ); return false ;/ " id=/ " LinkButton1/ " href=/ " javascript:__doPostBack('LinkButton1','')/ " style=/ " Z - INDEX: 101 ; LEFT: 416px; POSITION: absolute; TOP: 96px/ " >Test</a> " }, " script " :[ " window.location = 'http://www.sina.com.cn'; " ]}
---------------------------
确定
---------------------------
Windows Internet Explorer
---------------------------
{ " value " : null , " error " : null , " viewState " : " /wEPDwUKMTQ4NzkxOTExMGRkLHCpj5eYh3HaWUC4wwfnI1kE8sI= " , " eventValidation " : " /wEWAgKw5r+UAwLM9PumD2DQQ4RF4lRuD5Qz+1A07BOdo0rx " , " controls " :{ " LinkButton1 " : " <a οnclick=/ " Anthem_FireCallBackEvent( this ,event,'LinkButton1','', true ,'','','', true , null , null , null , true , true ); return false ;/ " id=/ " LinkButton1/ " href=/ " javascript:__doPostBack('LinkButton1','')/ " style=/ " Z - INDEX: 101 ; LEFT: 416px; POSITION: absolute; TOP: 96px/ " >Test</a> " }, " script " :[ " window.location = 'http://www.sina.com.cn'; " ]}
---------------------------
确定
---------------------------
看上去有点乱,我们把它还原为正常的 js 代码,实际上是这样一个对象:
JavaScript:
{
" value " : null ,
" error " : null ,
" viewState " : " /wEPDwUKMTQ4NzkxOTExMGRkLHCpj5eYh3HaWUC4wwfnI1kE8sI= " ,
" eventValidation " : " /wEWAgKw5r+UAwLM9PumD2DQQ4RF4lRuD5Qz+1A07BOdo0rx " ,
" controls " : {
" LinkButton1 " : " <a οnclick=/ " Anthem_FireCallBackEvent( this ,event,'LinkButton1','', true ,'','','', true , null , null , null , true , true ); return false ;/ " id=/ " LinkButton1/ " href=/ " javascript:__doPostBack('LinkButton1','')/ " style=/ " Z - INDEX: 101 ; LEFT: 416px; POSITION: absolute; TOP: 96px/ " >Test</a> " ,
},
" script " : [
" window.location = 'http://www.sina.com.cn'; "
]
}
" value " : null ,
" error " : null ,
" viewState " : " /wEPDwUKMTQ4NzkxOTExMGRkLHCpj5eYh3HaWUC4wwfnI1kE8sI= " ,
" eventValidation " : " /wEWAgKw5r+UAwLM9PumD2DQQ4RF4lRuD5Qz+1A07BOdo0rx " ,
" controls " : {
" LinkButton1 " : " <a οnclick=/ " Anthem_FireCallBackEvent( this ,event,'LinkButton1','', true ,'','','', true , null , null , null , true , true ); return false ;/ " id=/ " LinkButton1/ " href=/ " javascript:__doPostBack('LinkButton1','')/ " style=/ " Z - INDEX: 101 ; LEFT: 416px; POSITION: absolute; TOP: 96px/ " >Test</a> " ,
},
" script " : [
" window.location = 'http://www.sina.com.cn'; "
]
}
其中 controls 是需要更新 innerHTML 的客户端控件集合,以及要更新的源代码。
Anthem.NET 修改了常见默认控件的 Render 方法,使控件输出的 HTML 外围多了一个容器控件. 而每次回调后,都会通过这个人为添加的容器来更新其中的控件 HTML 输出。
看如下 HTML:
HTML:
<span id="Anthem_LinkButton1__"
><
a
id
="LinkButton1"
onclick
="Anthem_FireCallBackEvent(this,event,'LinkButton1','',true,'','','',true,null,null,null,true,true);return false;"
href
="javascript:__doPostBack('LinkButton1','')"
style
="Z-INDEX: 101; LEFT: 416px; POSITION: absolute; TOP: 96px"
>
Test
</
a
></
span>
这段代码中,span 便是 LinkButton 的容器。
上述返回对象中的 script 属性,是在服务器端设定的,需要在返回后执行的脚本代码的集合。
服务器端可以通过下列语句来添加脚本:
C#:
Anthem.Manager.AddScriptForClientSideEval(
"
window.location = 'http://www.sina.com.cn';
"
);
以上分析的是 Anthem 在正常工作的情况下输出的对象,那么错误时会输出什么内容呢?下面是一个例子:
---------------------------
Microsoft Internet Explorer
---------------------------
< html > < head > < title > δʵ��÷������/title> < style > body { font-family : "Verdana" ; font-weight : normal ; font-size : .7em ; color : black ; } p { font-family : "Verdana" ; font-weight : normal ; color : black ; margin-top : -5px } b { font-family : "Verdana" ; font-weight : bold ; color : black ; margin-top : -5p
Microsoft Internet Explorer
---------------------------
< html > < head > < title > δʵ��÷������/title> < style > body { font-family : "Verdana" ; font-weight : normal ; font-size : .7em ; color : black ; } p { font-family : "Verdana" ; font-weight : normal ; color : black ; margin-top : -5px } b { font-family : "Verdana" ; font-weight : bold ; color : black ; margin-top : -5p
我们看到其中有乱码信息,可以判断 Anthem 是遇到了编码问题导致输出错误了。
于是重新设定页面的编码,解决了这个问题。
分析一下 Anthem 的实现,可以看到 Anthem 在发送请求时的设定代码:
JavaScript:
x.open(
"
POST
"
, url
?
url : Anthem_DefaultURL, clientCallBack
?
true
:
false
);
x.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded; charset=utf-8 " );
x.setRequestHeader( " Accept-Encoding " , " gzip, deflate " );
x.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded; charset=utf-8 " );
x.setRequestHeader( " Accept-Encoding " , " gzip, deflate " );
其默认请求编码是 utf-8 的。
而其输出编码,则可以通过 web.config 来定制。方法如下:
<
configuration
>
< system .web >
< appSettings >
< add key ="Anthem.ResponseEncoding" value ="gb2312" />
< add key ="Anthem.ResponseType" value ="gb2312" />
</ appSettings >
</ system.web >
</ configuration >
< system .web >
< appSettings >
< add key ="Anthem.ResponseEncoding" value ="gb2312" />
< add key ="Anthem.ResponseType" value ="gb2312" />
</ appSettings >
</ system.web >
</ configuration >
这个办法是我通过分析 Anthem 的源码发现的,奇怪的是在其文档中好像没有发现相关的说明。
相关代码如下:
Manager.cs (C#):
private
void
ConfigureResponse(HttpResponse resp) {
string contentEncoding = null ;
string contentType = null ;
#if V2
contentEncoding = WebConfigurationManager.AppSettings[ " Anthem.ResponseEncoding " ];
contentType = WebConfigurationManager.AppSettings[ " Anthem.ResponseType " ];
#else
contentEncoding = ConfigurationSettings.AppSettings[ " Anthem.ResponseEncoding " ];
contentType = ConfigurationSettings.AppSettings[ " Anthem.ResponseType " ];
#endif
if (contentEncoding != null )
resp.ContentEncoding = Encoding.GetEncoding(contentEncoding);
if (contentType != null )
resp.ContentType = contentType;
resp.Cache.SetCacheability(HttpCacheability.NoCache);
}
string contentEncoding = null ;
string contentType = null ;
#if V2
contentEncoding = WebConfigurationManager.AppSettings[ " Anthem.ResponseEncoding " ];
contentType = WebConfigurationManager.AppSettings[ " Anthem.ResponseType " ];
#else
contentEncoding = ConfigurationSettings.AppSettings[ " Anthem.ResponseEncoding " ];
contentType = ConfigurationSettings.AppSettings[ " Anthem.ResponseType " ];
#endif
if (contentEncoding != null )
resp.ContentEncoding = Encoding.GetEncoding(contentEncoding);
if (contentType != null )
resp.ContentType = contentType;
resp.Cache.SetCacheability(HttpCacheability.NoCache);
}
小结一下使用 Anthem.NET 碰到脚本问题的查错方法:
首先定位到 Anthem.NET 产生的某个具体函数,然后,可以在页面的 </body> 前插入代码来改写该函数,在其中加入调试语句来定位问题。
当然,以上所说的是在部署服务器这种受限的环境下(通常没有开发环境)排错的方法,如果能够直接调试页面的 JavaScript 就更方便了。比如可以用 Visual Studio, 或者 MSE.exe 等工具来调试。