分享
 
 
 

错误分析和AJAX(XMLHttpRequest)

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

即使你现在还没有听说,AJAX已经成为web技术领域最热门的词(就象Adaptive Path上的一篇文章提到的一样)。AJAX框架的关键是名为XMLHttpRequest的JavaScript对象,通过它客户端开发人员可以在不打断用户操作或者在充分使用隐藏表单的情况下通过HTTP直接发送和接收XML文档。现在,有些人可能会有这种忧虑,让那些以前只做表单(form)校验和增加图片动画效果的客户端开发人员突然间负责分析XML文档结构,以及与HTTP协议的header部分打交道,这能行吗?但是,没有风险就没有回报。为了减轻这种疑惑,我将展示如何使用XMLHttpRequest实现以前无法实现功能,同时如何减少程序错误和如何提高程序质量。

XMLHttpRequest和XML DOM的JavaScript基础

首先,我们需要声明一些规则。现在常用的浏览器(IE, Mozilla, Safari, Opera)都特别提供了对XMLHttpRequest对象的支持,同时也广泛支持XML DOM,虽然和往常一样:微软(Microsoft)使用了一种稍微有些不同的实现并有一些需要特殊注意的地方。和我们那些更进取的朋友直接实现XMLHttpRequest不同,IE需要你创建一个具有相同属性的ActiveXObject对象的实例。Apple Developer Connection网站上有一篇非常好的文章总览了XMLHttpRequest,并列举了它的全部特性。

下面是个基础的例子:

var req;function postXML(xmlDoc) {if (window.XMLHttpRequest) req = new XMLHttpRequest();

else if (window.ActiveXObject) req = new ActiveXObject("Microsoft.XMLHTTP");

else return;

// fall on our swordreq.open(method, serverURI);

req.setRequestHeader('content-type', 'text/xml');

req.onreadystatechange = xmlPosted;req.send(xmlDoc);

}function xmlPosted() {if (req.readyState != 4) return;

if (req.status == 200) {var result = req.responseXML;

} else {// fall on our sword}}

这个强大的工具应用前景非常广泛,而且对其潜在应用方面的探索才刚刚开始。但是在任何准备在网上建立XML园地的人失控前,我建议我们先架起一个安全网以防止任何抱负极高的人摔断他们的脖子。

JavaScript错误处理基础

JavaScript在其早期版本就支持简单的错误处理,但是非常简陋,只有少数的特性,并且实现的很差。新近的浏览器不仅支持了类似于C++和Java用于错误处理的关键字try/catch/finally,而且实现了onerror事件提供捕捉在运行期产生的任何错误。其使用方法非常简单而且直接:

function riskyBusiness() {try {riskyOperation1();

riskyOperation2();

} catch (e) {// e是错误类型对象// 至少有两个属性:name及message} finally {// 清理工作}}window.onerror = handleError;

// 架起捕获错误的安全网function handleError(message, URI, line) {// 提示用户,该页可能不能正确回应return true;

// 这将终止默认信息}

一个实例:将客户端的错误传递个服务器

现在我们已经了解了XMLHttpRequest和JavaScript错误处理的基础,让我们通过一个简单的例子来看一下如何将这两个联系在一起使用。你也许会认为JavaScript错误应该很容易通过状态栏的黄色三角认出,但是我仍然在几个可靠组织的面向公众的网站上发现他们躲过了质量评估部门。

因此,在这我将提供一种捕捉错误并将他们在服务器上记录,希望能够提醒某个人去修改这些错误。首先,我们考虑客户端。客户端需要提供一个产生日志记录的类,这个类在使用时必须只实例化一次,并能够透明地处理那些复杂的细节。

我们首先创建构造器:

// 一个类构造方法function Logger() {// 域this.req;

// 方法this.errorToXML = errorToXML;

this.log = log;}

其次,我们定义一个将Error对象转成XML的方法。默认情况下,Error对象只有两个属性:name和message,但我们需要核对第三个可能很有用属性location。

// 将一个错误映射到XML文档function errorToXML(err) {var xml = '<?xml version="1.0"?>\n' +'<error>\n' +'<name>' + err.name + '</name>\n' +'<message>'+ err.message + '</message>\n';if (err.location) xml += '<location>' + err.location + '</location>';xml += '</error>';return xml;}

接着是log方法。这是这段脚本将上述两个原则(XMLHttpRequest和XML DOM)结合在一起的最基础部分。注意我们使用了POST方法。在这我本质上是创建了一个只写的定制的web服务,在每一次成功的请求时它会建立一些新纪录。因此,使用POST是唯一可行的方法。

// Logger类的日记方法function log(err) {// 嗅探环境if (window.XMLHttpRequest) this.req = new XMLHttpRequest();else if (window.ActiveXObject) this.req =new ActiveXObject("Microsoft.XMLHTTP");

else return; // 无功而返// 确定方式及URIthis.req.open("POST", "/cgi-bin/AjaxLogger.cgi");

// 设定request的headers。 如果错误出现在一个所包含的.js文件中,//REFERER 这个最顶层的URI可能会与产生错误的地方不一致this.req.setRequestHeader('REFERER', location.href);

this.req.setRequestHeader('content-type', 'text/xml');

// 请求完毕时要调用的函数this.req.onreadystatechange = errorLogged;

this.req.send(this.errorToXML(err));

// 如果不能在10秒在完成请求,// 需事务处理this.timeout = window.setTimeout("abortLog();", 10000);}

最后是实例化日志记录类。注意这个类只能有一个实例。

// logger只能有一个实例var logger = new Logger();

最后还有两个我们的类里调用的方法。如果在记录错误时发生错误,除了告诉用户我们没有其它的办法。如果运气好的话,这种情况并不会出现。因为浏览器的事件(event)不会拥有我们的对象的引用,但是会引用我们创建的logger实例,所以这两个方法不是日志记录类的方法。

// 尽管已经尝试,但如果有连接错误,放弃吧function abortLog() {logger.req.abort();

alert("Attempt to log the error timed out.");}// 当request状态有变化则调用function errorLogged() {if (logger.req.readyState != 4) return;window.clearTimeout(logger.timeout);

// 请求完毕if (logger.req.status >= 400)alert('Attempt to log the error failed.');}

以上所有的代码都可以写在一个.js文件里,你可以在任何一个(或者所有)的页面里引入这个文件。下面是这个例子展示了如何引入并使用这个文件:

<script type="text/javascript" src="Logger.js">

</script>

<script type="text/javascript">

function trapError(msg, URI, ln) {

// 将未知错误包装进一个对象var error = new Error(msg);error.location = URI + ', line: ' + ln;

// 增加定制属性logger.log(error);warnUser();return true;

// 避免出现黄色三角形符号}window.onerror = trapError;

function foo() {try {riskyOperation();

} catch (err) {

//增加定制属性err.location = location.href + ', function: foo()';

logger.log(err);warnUser();

}}function warnUser() {alert("An error has occurred while processing this page."+"Our engineers have been alerted!");// 错误处理location.href = '/path/to/error/page.html';

}</script>

现在我们已经知道如何将日志和HTML页面整合,剩下的就是如何接收和解析客户端传递到服务器的消息。我使用了大家易接受的CGI脚本来实现这个功能,在这个脚本里我用了XML::Simple(我最喜欢的模块之一)来解析提交上来的数据,并且用CGI::Carp将结果直接写到httpd(http服务程序)的错误日志里,这样你的系统管理员就不用去监控另一个日志。这个脚本里还包含了一些好的例子来说明如何对不同的成功和失败条件编写对应的响应代码。

use CGI;use CGI::Carp qw(set_progname);use XML::Simple;

my $request = CGI->new();my $method = $request->request_method();

# method must be POSTif ($method eq 'POST') { eval {

my $content_type = $request->content_type();

if ($content_type eq 'text/xml') {

print $request->header(-status =>

'415 Unsupported Media Type', -type => 'text/xml');

croak "Invalid content type: $content_type\n";

}

# when method is POST and the content type is neither

# URI encoded nor multipart form, the entire post

# is stuffed into one param: POSTDATA

my $error_xml = $request->param('POSTDATA');

my $ref = XML::Simple::XMLin($error_xml);

my ($name, $msg, $location) =

($ref->{'name'}, $ref->{'message'}, '');

$location = $ref->{'location'} if (defined($ref->{'location'}));

# this will change the name of the carper in the log

set_progname('Client-side error');

my $remote_host = $request->remote_host();

carp "name: [$name], msg: [$msg], location: [$location]";

};

if ($@) {

print $request->header(-status => '500 Internal server error',

-type => 'text/xml');

croak "Error while logging: $@";

} else {

# this response code indicates that the operation was a

# success, but the client should not expect any content

print $request->header(-status => '204 No content',

-type => 'text/xml');

}} else { print $request->header(-status => '405 Method not supported',

-type => 'text/xml');

croak "Unsupported method: $method";}

以上就是全部的代码了。现在,当下次有一些有问题的JavaScript代码溜进系统时,你可以想象你的日志监控人员开始闪动红色的灯,而你的客户端开发人员在半夜接到电话的情景

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有