选择显示字体大小

错误和ajax

错误和ajax

作者: joshua gitlin

may 11, 2005

翻译: niuji



版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
英文原文地址:
http://www.xml.com/pub/a/2005/05/11/ajax-error.html
中文地址:
http://www.matrix.org.cn/resource/article/43/43667_ajax.html
关键词: ajax error




即使你现在还没有听说,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 sword
req.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=&quot;1.0&quot;?>\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(&quot;microsoft.xmlhttp&quot;);
else return; // 无功而返
// 确定方式及uri
this.req.open(&quot;post&quot;, &quot;/cgi-bin/ajaxlogger.cgi&quot;);
// 设定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(&quot;abortlog();&quot;, 10000);
}


最后是实例化日志记录类。注意这个类只能有一个实例。
// logger只能有一个实例
var logger = new logger();


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

// 尽管已经尝试,但如果有连接错误,放弃吧
function abortlog() {
logger.req.abort();
alert(&quot;attempt to log the error timed out.&quot;);
}

// 当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=&quot;text/javascript&quot; src=&quot;logger.js&quot;></script>
<script type=&quot;text/javascript&quot;>
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(&quot;an error has occurred while processing this page.&quot;+
&quot;our engineers have been alerted!&quot;);
// 错误处理
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 post
if ($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 &quot;invalid content type: $content_type\n&quot;;
                }
                # 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 &quot;name: &#91;$name&#93;, msg: &#91;$msg&#93;, location: &#91;$location&#93;&quot;;
        };
        if ($@) {
                print $request->header(-status => '500 internal server error',
                        -type => 'text/xml');
                croak &quot;error while logging: $@&quot;;
        } 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 &quot;unsupported method: $method&quot;;
}


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



 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons