第20章 JavaScript通信

在传统Web开发中,客户端与服务器端通信主要通过同步请求(页面刷新)来实现,当客户端向服务器端发出HTTP请求之后,服务器端接收并处理这个请求,然后响应完整的Web页面给客户端。这样当发出请求之后,用户就需要慢慢等待,直到服务器响应完毕。如果同步交互的信息和次数很多,这中间就会有大量无用,或者重复性数据挤占带宽。

Ajax完全摒弃了这种信息交互方式,它通过在客户端嵌入一个中间件(XMLHttpRequest组件),并专门负责客户端与服务器端通信,这样就不需要刷新页面,浏览器也能够通过这个中间件随时随地与服务器端保持异步通信和联系,服务器端响应的数据也不再是一个完整的页面,而是根据需要响应信息。

这样数据交互由传统的表单提交来发送一个HTTP请求,转换为JavaScript调用Ajax引擎来实现。响应信息也不用需要服务器端进行深加工,所有数据通常以XML、JSON或文本格式返回,并在客户端由JavaScript进行处理和呈现。由于交互都是以异步的方式实现,用户就不会因为浏览器被锁定而中断其他任务的操作。

【学习重点】

▲ 了解HTTP和Ajax技术

▲ 能够使用隐藏框架实现异步通信

▲ 能够使用JSONP设计异步通信

▲ 使用Ajax设计异步通信

▲ 掌握异步信息交互的请求、响应接收和监测

20.1 HTTP概述

HTTP(HyperText Transfer Protocol,超文本传输协议)是一种应用层协议,专门负责超文本的传输,如传输网页、图像、不同类型文件等。这套规则涉及互联网底层协议(TCP/IP)、应用层协议(如文件传输协议FTP、电子邮件传输协议SMTP、域名系统服务DNS、网络新闻传输协议NNTP)、数据传输与交换规则,以及数据完整性与安全性等各种专业技术话题。

HTTP主要由两部分组成:请求(Request)和响应(Response),简单说明如下。

HTTP请求信息由3部分组成:请求行、消息报头、请求正文(可选)。请求的格式如下:

     <request-line><headers><blank line>[<request-body>]

请求行以一个方法符号开头,以空格分隔,后面跟着请求的URI和协议的版本。格式如下:

Method Request-URI HTTP-Version CRLF

请求行各部分说明如下。

☑ Method:表示请求方法,请求方法以大写形式显示,各种方法说明如表20-1所示。

表20-1 请求方法

☑ Request-URI:表示统一资源标识符。

☑ HTTP-Version:表示请求的HTTP协议版本。

☑ CRLF:表示回车和换行,除了作为结尾的CRLF外,不允许出现单独的CR或LF字符。请求行后是消息报头部分,用来说明服务器需要调用的附加信息。

在消息报头后是一个空行,然后才是请求正文部分,即称之为主体部分(body),该部分可以添加任意的其他数据。

HTTP定义了大量的请求类型,不过Web开发常用GET和POST请求。只要在Web浏览器上输入一个URL,浏览器就将基于该URL向服务器发送一个GET请求,以告诉服务器获取并返回什么资源。

【示例1】在浏览器地址栏中输入www.baidu.com,则GET请求如下:

请求行的第一部分说明了该请求是GET请求。该行的第二部分是一个斜杠(/),用来说明请求的是百度域名的根目录。该行的最后一部分说明使用的是HTTP 1.1版本,另一个可选项是HTTP 1.0。

第二行是请求的第一个消息报头,HOST头部指出请求的域名。结合HOST头部和上一行中的统一资源标识符(即斜杠),就可以确定请求服务器的具体地址。

第三行包含的是User-Agent头部,服务器端和客户端脚本都能够访问它,该头部包含的信息由浏览器来定义,并且在每个请求中将会自动发送。JavaScript和服务器通过User-Agent头部信息,可以了解客户端的本地情况。

最后一行是Connection头部,通常将浏览器操作设置为Keep-Alive,在最后一个头部后有一个空行(即使不存在请求主体)。

【示例2】如果在GET请求中附带参数,则必须将这些参数信息附在URL后面,这个信息也被称之为查询字符串(Query String),发送时将被附加在请求行中,格式如下:

【示例3】POST方法要求被请求服务器接收附在请求后面的数据,常用于提交表单。格式如下:

POST请求与GET请求之间略有区别。首先,请求行开始处的GET变为POST,在后面有两个新行。其中Content-Type说明了请求主体的内容是如何编码的。浏览器始终以application/x-www-form-urlencoded的编码格式来传送数据,这是针对简单URL编码的MIME类型。

Content-Length说明了请求主体的字节数。在Connection后是一个空行,再后面就是请求主体。与大多数浏览器的POST请求一样,都是以“名称/值”对的形式表示的。HEAD方法与GET方法的数据传输形式几乎是一样的。

HTTP响应也由3部分组成:状态行、消息报头、响应正文(可选)。HTTP响应格式如下:

     <status-line><headers><blank line>[<response-body>]

其中状态行格式如下:

     HTTP-Version Status-Code Reason-Phrase CRLF

状态行的组成说明如下。

☑ HTTP-Version:表示服务器HTTP协议的版本。

☑ Status-Code:表示服务器发回的响应状态代码。

☑ Reason-Phrase:表示状态代码的文本描述。

状态代码由3位数字组成,第一个数字定义了响应的类别,且有5种可能取值。

☑ 1xx:指示信息。表示请求已接收,继续处理。

☑ 2xx:成功。表示请求已被成功接收、理解或接受。

☑ 3xx:重定向。要完成请求必须进行更进一步的操作。

☑ 4xx:客户端错误。请求有语法错误,或者请求无法实现。

☑ 5xx:服务器端错误。服务器未能实现合法的请求。

常见状态码、状态描述、说明如下:

【示例4】下面是一个HTTP响应的示例:

在状态行之后是消息头。一般服务器会返回一个名为Data的信息,用来说明响应生成的日期和时间。接下来就是与POST请求中一样的Content-Type和Content-Length。响应主体所包含的就是所请求资源的HTML源文件。

20.2 使用隐藏框架

异步通信就是在不刷新页面的情况下,允许客户端与服务器端进行不连续通信。这样用户不需要等待,网页浏览与信息交互互不干扰,信息传输不用再传输大量无用、重复的代码。

20.2.1 认识隐藏框架

所谓隐藏框架,就是设置框架页显示高度为0,以达到隐藏显示的目的。隐藏框架常用来加载一些外部链接和导入一些扩展服务,其中使用最多的就是隐藏框架导入广告页。

也可以使用隐藏框架实现异步通信,关于这种技术也被称为远程脚本(Remote Scripting)技术,即远程(函数)调用。

远程脚本技术的设计思路:创建一个隐藏框架,利用该框架载入服务器端指定的文件,此时被载入的服务器端文件所包含的远程脚本(即JavaScript代码)就被激活,然后激活的脚本把服务器端需要传递的信息通过框架页加载响应给客户端,从而实现客户端与服务器异步通信的目的。

【示例】下面对远程脚本技术进行分解。首先,使用一个简单的示例演示如何使用框架来实现异步通信的目的。具体操作步骤如下。

第1步,新建一个简单的框架集(index.htm),其中第一个框架默认加载页面为客户交互页面,第二个框架加载的页面是一个空白页(可以不包含任何内容):

第2步,设计空白页(black.htm)的页面代码如下:

第3步,在客户交互页面(main.htm)中定义一个简单的交互按钮,当单击该按钮时将为底部框架加载服务器端的请求页面(server.htm):

第4步,在服务器响应页面(server.htm)利用JavaScript脚本动态改变客户交互页面的显示信息:

第5步,在浏览器中预览index.htm,然后就可以看到如图20-1所示的演示效果。

图20-1 异步交互通信演示图

20.2.2 案例:使用隐藏框架设计异步交互

隐藏框架只是异步交互的一种载体,它仅负责信息的传输,而交互的核心是应该有一种信息处理机制,这种处理机制就是回调函数。所谓回调函数,就是客户端页面中的一个普通函数,但是该函数是在服务器端被调用,并负责处理服务器端响应的信息。另外,在异步交互过程中,还需要信息的双向交互,而不仅仅是接受服务器端的信息。

下面示例演示如何把客户端的信息传递给服务器端,同时让服务器准确接收客户端信息。本示例初步展现了异步信息交互中请求和响应的完整过程,其中回调函数的处理又是整个流程的焦点。具体操作步骤如下:

第1步,模仿20.2.1节示例构建一个框架集(index.htm)。代码如下:

这个框架集由上下两个框架组成,第二个框架高度为0,但是不要设置为0像素高,因为在一些老版本的浏览器中会依然显示。这两个框架的分工如下。

☑ 框架1(main):负责与用户进行信息交互。

☑ 框架2(server):负责与服务器进行信息交互。

考虑到老版本浏览器可能会不支持框架技术,所以应使用<noframes>来兼容它们,使设计看起来会更友好。

第2步,在默认状态下,框架集中第二个框架加载一个空白页面(black.htm),第一个框架中加载与客户进行交互的页面(main.htm)。

第一个框架中主要包含两个函数:一个是响应用户操作的回调函数,另一个是向服务器发送请求的事件处理函数:

由于回调函数是在服务器端文件中被调用的,所以对象作用域的范围就发生了变化,此时应该指明它的框架集和框架名或序号,否则在页面操作中会找不到指定的元素。

第3步,在服务器端的文件中设计响应处理函数,该函数将分解HTTP传递过来的URL信息,获取查询字符串,并根据查询字符串中的用户名和密码,判断当前输入的信息是否正确,并决定具体响应的信息。

在实际开发中,服务器端文件一般为动态服务器类型的文件,并借助服务器端脚本来获取用户的信息,然后决定响应的内容,如查询数据库,返回查询内容等。本示例以简化的形式演示异步通信的过程,因此没有采用服务器技术。

第4步,预览框架集,在客户交互页面中输入用户的登录信息,当向服务器提交请求之后,服务器首先接收从客户端传递过来的信息,并进行处理,然后调用客户端的回调函数把处理后的信息响应回去。示例演示效果如图20-2所示。

图20-2 异步交互和回调处理效果图

20.2.3 使用iframe

使用框架集设计异步交互存在很多问题:

☑ 页面被深深地打上框架的烙印,不利于结构的优化,浏览器的支持也受到很多限制,需要更多的文件进行配合使用。

☑ 框架集缺乏灵活性,如果希望完全使用脚本控制异步请求与交互,就非常不方便。

于是就引入了浮动框架(iframe)技术。iframe与frameset(框架集)都可以实现动态加载客户端或服务器端任何类型的网页文件,也就是说它们的功能相同,但是表现形式各异。iframe被定义为文档结构元素,与页面中其他普通元素无异,完全与框架集无关,但是frameset被定义为窗口元素,与html、head和body等基本文档结构元素平行使用,可以说它们分别属于不同级别的元素。因此,浮动框架可以插入到页面中的任意位置,与页面中其他元素能够很好地融合。同时开发人员还可以在JavaScript脚本中动态创建iframe元素并进行控制,这就给异步交互开发带来新的活力。

【示例】下面以20.2.2节示例为基础进行扩展,具体操作步骤如下。

第1步,在客户端交互页面(main.html)中新建函数hideIframe(),使用该函数动态创建浮动框架,借助这个浮动框架实现与服务器进行异步通信:

当使用DOM创建iframe元素时,应注意设置同名的name和id属性,因为不同类型浏览器引用框架时会分别使用name或id属性值。当创建好iframe元素之后,大部分浏览器(如Mozilla和Opera)会需要一点时间(约为几毫秒)来识别新框架并将其添加到帧集合中,因此当加载地址准备向服务器进行请求时,应该使用setTimeout()函数使发送请求的操作延迟10毫秒。这样当执行请求时,浏览器能够识别这些新的框架,避免发生错误。

如果页面中需要多处调用请求函数,则建议定义一个全局变量,专门用来存储浮动框架对象,这样就可以避免每次请求时都创建新的iframe对象。

第2步,修改客户端交互页面中request()函数的请求内容,直接调用hideIframe()函数,并传递URL参数信息。

由于浮动框架与框架集是属于不同级别的作用域,浮动框架是被包含在当前窗口中的,所以应该使用parent,而不是parent.frames[0]来调用回调函数,或者在回调函数中读取文档中的元素(客户端交互页面的详细代码请参阅iframe_main.html文件):

第3步,在服务器端响应页面中也应该修改引用客户端回调函数的路径(服务器端响应页面详细代码请参阅server.html文件)。代码如下:

这样通过iframe浮动框架只需要两个文件:客户端交互页面(main.html)和服务器端响应页面(server.html),就可以完成异步信息交互的任务。该示例的演示效果同20.2.2节相同,只不过完善了部分代码,因此就不再进行演示和代码详解,用户可以参阅本书示例源代码了解更具体的代码和运行效果。

20.3 使用JSONP

JavaScript代码不仅可以执行,还可以作为一种数据,进行信息传递,利用这种数据格式可以开发更清洁的异步交互技术,解决如何实现跨域异步通信问题。本节将详细介绍JSON数据格式和使用技巧。

20.3.1 认识<script>标签

<script>标签能够动态加载外部JavaScript脚本文件。JavaScript脚本文件不仅仅可以被执行,还可以传输数据,所以在服务器端使用JavaScript文件来附加传递响应信息,当在客户端使用script元素加载远程脚本文件时,这些附加在JavaScript文件中的响应信息也一同被加载到客户端,这样就可以设计异步信息交互的目的。

【示例】新建一个客户端信息交互和请求页面(script_main.htm),然后输入下面的代码:

上面的代码比较普通,似乎没有什么特殊之处,不过它多了一行<script>标签代码,该标签导入外部JavaScript脚本文件,这个文件可以位于本地目录,也可以远在服务器端,此时可以假设本页面将要导入的是服务端请求脚本文件。

然后,在服务端的script_server.js脚本文件中调用回调函数callback(),代码如下:

     //服务器端响应页面callback("Hi, 大家好,我是从服务器端过来的信息使者。");

此时,如果运行客户端交互页面(script_main.htm),在客户端交互页面中将弹出“Hi,大家好,我是从服务器端过来的信息使者。”的响应信息,这些信息来自于服务器端。

当服务器端JavaScript文件被加载到客户端交互页面中时,它包含的脚本就成为交互页面作用域中的一部分,也就是说,script_server.js文件中的脚本实际上已经成为script_main.htm页面脚本的一部分,即最终的运行结果应该是这样的:

提示:本示例也存在几个问题:

☑ 异步交互的本质是可控的信息交流。但是上面示例代码在页面初始化之后就完成了异步信息交互流程。

☑ 上面示例是在预知客户端交互页面中的回调函数的名称情况下,直接在服务端的JavaScript脚本文件中进行引用的。但在实际开发中,用户很难预知回调函数的名称。

☑ 在异步交互中,信息该如何传输呢,服务器端的响应信息又该如何附加到JavaScript脚本中呢?

20.3.2 案例:脚本化script元素

20.3.1节初步分析了使用script元素实现异步交互的可能性,下面讲解如何使用script元素设计异步交互接口,动态生成script元素。通过script元素实施异步交互功能的封装,这样就避免了每次实施异步交互时都需要手动修改文档结构的麻烦。具体操作步骤如下:

第1步,定义一个异步请求的封装函数。

第2步,完善客户端交互页面的结构和脚本代码。上面这个请求函数是整个script异步交互的核心。下面就可以来设计客户端交互页面(main.html):

第3步,在服务器端的响应文件(server.js)中输入下面的代码:

     //服务器端响应页面callback("Hi, 大家好,我是从服务器端过来的信息使者。");

第4步,当预览客户端交互页面时,不会立即发生异步交互的动作,而当单击按钮时才会触发异步请求和响应行为,这正是异步交互所要的设计效果。

20.3.3 案例:传递参数

当使用script元素作为异步通信的工具时,实现信息交换的最简单的方法就是使用参数作为从客户端向服务器端传递信息,这种在URL中附加参数的方式是最快捷的方法,然后服务器端接收这些参数,并把响应信息以JavaScript脚本形式传回客户端。

【示例1】在客户端交互页面(main.htm)中以下面的形式向服务器发出请求:

     <html><head><title>异步信息交互</title><script src="code_server.js?id=8"></script><body><h1>客户端信息交互页面</h1></body></html>

在JavaScript外部文件的URL中附加了一个参数id=8,这个参数是客户端传递给服务器端,希望服务器能够接收该参数,并能够根据该参数响应相应的信息,传回这些响应信息。

使用Location对象的search属性能够捕获HTTP的URL查询字符串信息,在服务器端的code_server.js文件中输入下面代码:

     var queryString=location.search.substring(1);alert(queryString);

但是当运行客户端交互页面时,提示信息为空,说明服务器端并没有接收到这个参数,如果使用下面的代码接收HTTP中完整的URL字符串信息,则返回客户端交互页码的URL字符串,而不是链接的JavaScript文件URL(如“http://localhost/mysite/main.htm”字符串)。

     var queryString=location.href;alert(queryString);

这样看来,使用Location对象是不能接收客户端交互页面中包含的外部JavaScript连接文件的URL字符串信息的。

【示例2】在服务器端JavaScript文件中使用脚本来读取客户端交互页面中<script>标签的src属性值,本示例是在20.3.2节示例基础上修改服务器端的JavaScript文件代码(server.js):

上面的JavaScript文件是服务器端请求的脚本文件,然后运行客户端交互页面(main_js.htm),当单击其中的“请求”按钮之后,则弹出正确提示信息。

【示例3】下面尝试把script元素的src属性设置为请求服务器端脚本文件,而不是JavaScript文件。例如,以ASP服务器技术为例,可以这样进行请求(main_asp.htm):

这样,就可以利用服务器技术来接收请求传递的参数,代码如下(server.asp):

【拓展】在异步交互中,用户应注意字符编码一致性,具体说明如下。

☑ 服务器端脚本的编码(默认为65001,即国际通用编码),如在ASP脚本文件的第一行命令中CODEPAGE属性指定ASP脚本代码的编码。下面设置ASP脚本文件为国际通用编码。

     <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>

☑ 请求的服务器脚本文件所在页面的编码,也就是HTML文档的字符编码:

     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

☑ 当服务器向客户端响应信息时,在HTTP传输中所使用的字符编码,默认为UTF-8,即国际通用编码。如果服务器端脚本编码为中文简体,则应该在服务器端响应信息的头部定义信息的编码为gb2312。如ASP脚本文件可以这样设置:

     <%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%><%callback=Request.QueryString("callback")Response.AddHeader"Content-Type","text/html;charset=gb2312"Response.Write("callback('Hi, 大家好,我是从服务器端过来的信息使者。')")%>

☑ 在客户端交互页面中应该设置页面编码,与服务器端请求页面的编码类似:

     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

要确保在异步交互过程中不发生乱码现象,用户应该保证上面4个方面的字符编码是一致的,即可以统一使用国际通用编码,或者统一使用中文简体编码(936或GB2312)。默认为国际通用编码(即65001或UTF-8)。

用户还需要注意的是,虽然<script>标签src属性请求的是ASP文件,但是ASP响应的字符串是符合JavaScript语法规则的字符串,这些字符串被加载到客户端的<script>标签内部时,就会被转换为可以执行的JavaScript脚本代码。

【示例4】本示例把客户端和服务器端对应的文件代码全部整理出来,并遵循编码一致性原则,避免异步交互中出现乱码。

☑ 客户端交互页面的完整代码(main_asp(gb2312).htm)如下:

☑ 服务器端响应页面的完整代码(serve(gb2312).asp)如下:

在测试上面代码时,用户应确保在服务器环境下运行,否则会达不到预期结果。整个异步交互的过程如图20-3所示。

图20-3 异步交互和回调完整过程

20.3.4 案例:设计响应类型

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript的一个子集,采用完全独立于语言的文本格式,这使得JSON成为理想的数据交换格式,易于阅读和编写,同时也易于解析和生成。

【示例1】在服务器端的JavaScript文件中输入下面代码(server.js)。

callback是回调函数的名称,然后使用小括号运算符调用该函数,并传递一个JavaScript对象。在这个参数对象直接量中包含4个属性:title、link、modified、items。这些属性都可以包含服务器端响应信息。其中前3个属性包含的值都是字符串,而第4个属性items包含一个数组,数组中包含两个对象直接量。这两个对象直接量又包含3个属性:title、link和description。

通过这种方式可以在一个JavaScript对象中包含更多的信息,这样在客户端的<script>标签中就可以利用src属性把服务器端的这些JavaScript脚本作为响应信息引入到客户端的<script>标签中。

然后,在回调函数中通过对对象和数组的逐层遍历和分解,有序显示所有响应信息,回调函数的详细代码如下:

客户端交互页面(main.htm)的完整代码如下:

回调函数和请求函数的名称并不是固定的,用户可以自定义这些函数的名称。

最后,保存页面,在浏览器中预览,则演示效果如图20-4所示。

图20-4 响应和回调解析复杂的数据

【拓展】出于浏览器安全考虑,XMLHttpRequest和框架等只能够在同域内进行异步通信(即同源策略),因此用户不能使用Ajax或框架实现跨域通信。不过,JSONP是一种可以绕过同源策略的方法。

JSONP是JSON with Padding的简称,它能够通过在当前文档(客户端)中生成脚本标记(<script>标签)来调用跨域脚本(服务器端脚本文件)时使用的约定,这是一个非官方的协议。

JSONP允许在服务器端动态生成JavaScript字符串返回给客户端,通过JavaScript回调函数的形式实现跨域调用。现在很多JavaScript技术框架都使用JSONP实现跨域异步通信,如dojo、JQuery、Youtube GData API、Google Social Graph API、Digg API等。

【示例2】下面结合一个示例说明如何使用JSONP约定来实现跨域异步信息交互。

第1步,在客户端调用提供JSONP支持的URL服务,获取JSONP格式数据。所谓JSONP支持的URL服务,就是在请求的URL中必须附加在客户端可以回调的函数,并按约定正确设置回调函数参数,默认参数名为jsonp或callback。注意,根据开发约定,只要服务器能够识别即可。本例定义URL服务的代码如下:

     http://localhost/mysite/server.ASP?jsonp=callback&d=1

其中参数jsonp的值为约定的回调函数名。JSONP格式的数据就是把JSON数据作为参数传递给回调函数并传回。例如,如果响应的JSON数据为:

那么真正返回到客户端的脚本标记则如下所示:

第2步,当客户端向服务器端发出请求后,服务器应该完成两件事情:一是接收并处理参数信息,如获取回调函数名。二是要根据参数信息生成符合客户端需要的脚本字符串,并把这些字符串响应给客户端。例如,服务器端的处理脚本文件如下(server.asp):

包含在“<%”和“%>”分隔符之间的代码是ASP处理脚本。在该分隔符之后的是输出到客户端的普通字符串。在ASP脚本中,使用Response.Write()方法输出回调函数名和运算符号。其中还用到条件语句,判断从客户端传递过来的参数值,并根据参数值决定响应的具体信息。

第3步,在客户端设计回调函数。回调函数应该根据具体的应用项目,以及返回的JSONP数据进行处理。例如,针对上面返回的JSONP数据,把其中的数据列表显示出来,则代码如下:

第4步,设计客户端交互页面与信息展示。用户可以在页面中插入一个<div>标签,然后把输出的信息插入到该标签内。同时为页面设计一个交互按钮,单击该按钮将触发请求函数,并向服务器端发去请求。服务器响应完毕,JavaScript字符串传回到客户端之后,将调用回调函数,对响应的数据进行处理和显示。

     <div id="test"></div>

注意:由于JSON完全遵循JavaScript语法规则,所以JavaScript字符串会潜在地包含恶意代码。JavaScript支持多种方法动态地生成代码,其中最常用的就是eval()函数,该函数允许用户将任意字符串转换为JavaScript代码执行。

恶意攻击者可以通过发送畸形的JSON对象实现攻击目的,这样eval()函数就会执行这些恶意代码。为了安全,用户可以采取一些方法来保护JSON数据的安全使用。例如,使用正则表达式过滤掉JSON数据中不安全的JavaScript字符串:

这个正则表达式能够检查JSON字符串,如果没有发现字符串中包含的恶意代码,则再使用eval()函数把它转换为JavaScript对象。

20.4 使用Ajax

Ajax是Asynchronous JavaScript and XML的缩写,中文翻译为“异步JavaScript和XML”,它是利用JavaScript语言和XML数据实现客户端与服务器端进行异步通信的一种方法。Ajax主要由下面几部分组成:

☑ 基于标准的HTML结构和CSS样式。

☑ 通过DOM(Document Object Model)实现动态显示和交互。

☑ 通过XML和XSLT进行数据交换和处理。

☑ 使用XMLHttpRequest插件进行异步通信。

☑ 使用JavaScript实施逻辑控制,以便整合以上所有的技术。

20.4.1 认识XMLHttpRequest

微软在IE 5.0版本浏览器中以ActiveX组件的形式定义了XMLHttpRequest对象,在IE 7.0中微软把XMLHttpRequest对象升级为Window对象的属性。现代浏览器也先后增加对XMLHttpRequest对象的支持,把它作为一个JavaScript本地对象,而不是ActiveX外部组件。

尽管不同类型的浏览器在支持XMLHttpRequest的细节方面略有不同,但是,所有的浏览器都提供了相同的属性和方法,这样就避免了兼容性问题。XMLHttpRequest对象提供的属性如表20-2所示,所提供的方法如表20-3所示。

表20-2 XMLHttpRequest对象属性

表20-3 XMLHttpRequest对象方法

XMLHttpRequest对象提供了客户端与服务器端进行通信的协议。客户端可以通过XMLHttpRequest对象向Web服务器发送请求并使用DOM进行处理,然后再显示响应的数据。

XMLHttpRequest对象包含14个成员对象,这些属性和方法负责完成所有异步通信的控制,使用XMLHttpRequest对象实现异步通信一般需要下面几个步骤。

☑ 定义XMLHttpRequest对象实例。

☑ 调用XMLHttpRequest对象的open()方法打开服务器端特定文件的连接。

☑ 告诉XMLHttpRequest对象如何处理服务器返回的数据,即注册onreadystatechange事件处理函数。

☑ 调用XMLHttpRequest对象的send()方法发送请求。

提示:使用隐藏框架和script方式实现异步通信都是开发人员的一种自发行为,没有被标准化。如今Ajax已经成为客户端与服务器端进行异步通信的标准。如表20-4所示简单比较了使用XMLHttpRequest对象和script元素实现异步通信的功能支持情况。

表20-4 XMLHttpRequest对象与script元素实现异步通信比较

20.4.2 定义XMLHttpRequest对象

现代浏览器都支持XMLHttpRequest对象,但是在IE早期版本浏览器中主要使用ActiveXObject组件方式来创建XMLHttpRequest对象。

【示例1】为了兼容不同的浏览器,一般可以使用下面代码来实现:

在上面的代码中,首先定义变量xmlHttp,用来存储XMLHttpRequest对象。然后使用条件语句分别判断当前浏览器的兼容问题,并根据不同类型浏览器决定定义对象的方法。对于Mozilla、Safari等非IE浏览器来说,它们支持window.XMLHttpReques对象。如果window.XMLHttpRequest为真,就可以使用new XMLHttpRequest()方法来实例化XMLHttpRequest对象。由于IE浏览器支持ActiveXObject组件实现Ajax技术,可以使用new ActiveXObject("Msxml2.XMLHTTP")或new ActiveXObject("Microsoft.XMLHTTP")方法来实例化XMLHttpRequest对象。

【示例2】下面函数采用一种更高效的工厂模式把定义XMLHttpRequest对象功能进行封装,这样只要调用createXMLHTTPObject()方法就可以返回一个XMLHttpRequest对象:

上面函数首先创建一个数组,包含各种定义XMLHttpRequest对象的方法函数。第一个元素是创建一个本地对象,而其他元素将针对IE浏览器的不同版本尝试创建ActiveX对象。然后设置变量xmlhttp为false,表示不支持Ajax。接着遍历工厂内所有函数并尝试执行它们,为了避免发生异常,把所有调用函数放在try子句中执行,如果发生错误,则在catch子句中捕获异常,并执行continue命令,返回继续执行,而不是抛出异常。如果创建成功,则中止当前循环,并返回创建的XMLHttpRequest对象实例。

20.4.3 建立XMLHttpRequest连接

创建XMLHttpRequest对象之后,就可以使用该对象的open()方法建立一个HTTP请求,即使用open()方法打开客户端与服务器端之间的通信连接。其用法如下:

     o.open(Method, Url, Async, User, Password);

该方法包含5个参数,其中前两个参数是必需的。

☑ 参数o表示XMLHttpRequest对象实例。

☑ 参数Method表示HTTP方法,如POST、GET、PUT和PROPFIND,方法的名称不区分大小写。

☑ 参数Url表示请求的地址。可以是绝对地址,也可以是相对地址。

☑ 参数Async为可选选项,设置是否为异步通信,默认为true,表示可以异步;而取值为false时,表示必须同步通信。

☑ 参数User和Password表示请求的文件需要服务器进行验证,如果未指定,当服务器需要验证时,会弹出验证窗口要求进行验证。

实际上open()方法并没有真正执行请求。如果监控网络间数据传递,当调用open()方法时看不到任何数据传输。这里的open()实际上就是从逻辑上执行请求准备。例如:

     xmlHttp.open("GET","http://localhost/mysite/server.asp", false);

在上面的代码中,利用open()方法为xmlHttp对象建立了一个与server.asp文件的连接。此时open()方法包含以下3个参数。

☑ 第一个参数设置发送HTTP请求为GET方法,即以查询字符串的形式传输数据(把数据附加在URL后面),如果要上传大量数据,则应该使用POST方法。

☑ 第二个参数用来设置要打开的服务器文件(该文件可以是任意类型的文件),这里要打开的是服务器端mysite站点内的server.asp文件。

☑ 第三个参数用来指定不要异步请求。所谓异步就是发出请求之后,不需要等待服务器端的响应,用户可以继续执行其他操作。默认为true,表示异步请求。

当建立连接请求之后,就可以使用send()方法发送请求到HTTP服务器端,并接收服务器的响应。send()方法只有一个参数,该参数可以携带请求数据。如果不传递信息,则可以设置该方法的参数为null。

send()方法虽然能够接收服务器的响应,但是如何把接收的数据读取出来,还需要responseBody、responseStream、responseText和responseXML属性来实现。

【示例】下面结合一个简单的示例进行说明。在客户端交互页面中输入下面脚本,脚本前面省略了定义XMLHttpRequest对象的代码:

     xmlHttp.open("GET","server.asp", false);xmlHttp.send(null);alert(xmlHttp.responseText);

在服务器端文件(server.asp)中输入下面的字符串:

     Hello World

在浏览器中预览客户端交互页面,就会弹出一个提示对话框,显示“Hello World”的提示信息。该字符串是借助XMLHttpRequest对象建立的连接通道,从服务器端响应回来的字符串。

20.5 发送请求

使用XMLHttpRequest的open()方法建立与服务器端的连接,然后通过send()方法发送请求,并获取服务器端的响应信息。客户端向服务器端传递数据的方式有多种,比较常用的方法包括两种:POST和GET。

20.5.1 发送GET请求

GET方法通过查询字符串的方式来传递请求信息,这是最常见的一种请求类型,每次在浏览器地址栏中输入URL并打开页面时,其实就是在向服务器发送一个GET请求。

GET请求的参数通过问号(?)前缀附加在URL的末尾,参数是以连字符(&)连接的一个或多个名/值对。每个名称和值都必须在编码后才能用在URL中,用户可以在JavaScript中使用encodeURIComponent()方法进行编码,服务器端在接收这些数据时也必须使用decodeURIComponent()方法进行解码。URL最大长度为2048字符(2KB)。

当使用XMLHttpRequest对象发送一个GET请求时,只需将包含所有参数的URL传入open()方法,同时设置第一个参数值为“GET”。这样服务器就能够自动在URL后面的查询字符串中接收到客户端传递过来的信息。使用GET请求比较简单,也比较方便,它适合传递一些简单的参数信息,不易传输大容量或受保护的数据。

【示例】本示例在客户端交互页面(main.html)中定义一个请求连接,并以GET方式传递一个参数信息callback=functionName:

然后,在服务器端的请求文件(server.asp)中输入下面的代码,以便获取参数callback的值,并把该值响应给客户端:

     <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%><%callback=Request.QueryString("callback")Response.Write(callback)%>

在浏览器中预览客户端交互页面,单击其中的按钮时,会弹出一个提示对话框,显示所要传递的参数值。

20.5.2 发送POST请求

使用XMLHttpRequest对象发送HTTP请求的另一种常用类型就是POST方法,它与GET方法截然不同。POST请求支持发送任意格式、任意长度的数据,而不仅仅限于串行化字符串(名/值对)。一般来说,POST请求用于在表单中输入数据后的提交过程。

与GET请求相似,POST请求的参数也必须进行编码,并用连字符(&)进行分隔,这些参数在发送POST请求时,不会被附加到URL的末尾,而是作为send()方法的参数进行传递,然后被送到服务器端。如下:

     send("name1=value1&name2=value2…");

【示例1】结合20.5.1节示例,下面使用POST方法向服务器传递数据。其中在客户端交互页面中定义如下请求函数:

本示例的代码结构与20.5.1节示例的代码结构没有太大变化。但是在open()方法中设置第一个参数为POST。最关键的是增加了setRequestHeader()方法,该方法专门用来设置请求的消息头,这里必须定义请求消息的内容类型为“application/x-www-form-urlencoded”,它表示传递的是表单值,一般使用POST发送请求时都必须设置该选项,否则服务器会无法识别传递过来的数据。setRequestHeader()方法的语法格式如下:

     xmlhttp.setRequestHeader("Header-name","value");

为了方便服务器能够识别当前请求为Ajax异步请求,一般设置头部信息中User-Agent首部为XMLHTTP,以便于服务器端能够辨别出XMLHttpRequest异步请求和其他客户端普通请求。

     xmlhttp.setRequestHeader("User-Agent","XMLHTTP");

这样就可以在服务器端编写脚本分别为现代浏览器和不支持JavaScript的浏览器呈现不同的文档,以提高可访问性的手段。如果使用POST方法传递数据,就必须设置另一个首部信息:

用户可以在http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html中找到HTTP请求头信息的总览表。

然后在send()方法中附加要传递的值,该值是一个或多个“名/值”对,多个“名/值”对之间使用“&”分隔符进行分隔。这样在服务器端(如ASP脚本)就可以利用Request.Form()方法捕获所传递过来的值。

在“名/值”对中,“名”可以为表单域的名称(与表单域相对应),“值”可以是固定的值,也可以是一个变量。如果是变量,可以把表单域内包含的值直接传递给变量,再由变量负责把数据传递给服务器端。这时还必须把open()方法中的第三个参数设置为false,即关闭异步通信。如果不需要通过send()方法传递数据,则只要传递null作为参数值即可。然后在服务器端设计接收POST方式传递的数据,并进行响应。

     <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%><%callback=Request.Form("callback")Response.Write(callback)%>

用于发送POST请求的数据类型(Content Type)通常是application/x-www-form-urlencoded,这意味着我们还可以以text/xml或application/xml类型给服务器直接发送XML数据,甚至以application/json类型发送JavaScript对象。

【示例2】下面的示例将向服务器端发送XML类型的数据,而不是简单的串行化名/值对数据:

由于使用GET方式传递的信息量是非常有限的,而使用POST方式所传递的信息是无限的,且不受字符编码的限制,还可以传递二进制信息。对于传输文件,以及大容量信息时多采用POST方式。另外,当发送安全信息或XML格式数据时,也应该考虑选用这种方法来实现。

20.5.3 案例:把数据转换为串行字符串

从20.5.1节和20.5.2节的示例可以看到,GET和POST方法都是以串行化方式发送数据。串行数据有两种存在形式。

1.传输名/值对信息

这与JavaScript对象结构类似,多在GET参数中使用。例如,下面是一个包含3对名/值的JavaScript对象数据:

将上面原生JavaScript对象数据转换为串行格式显示为:

     user:"ccs8"&padd:"123456"&email:"css8@mysite.cn"
2.传输有序数据列表

这与JavaScript数组结构类似,多在一系列文本框中提交表单信息时使用,它与上一种方式不同,所提交的数据按顺序排列,不可以随意组合。例如,下面是一组有序表单域信息,它包含多个值:

将上面有序表单数据转换为串行格式显示为:

     text:"ccs8"& text:"123456"& text:"css8@mysite.cn"

不管是GET方法,还是POST方法发送数据,数据最终都被转换为串行格式提交。因此,可以把这个数据转换过程进行功能封装,详细代码如下:

20.6 异步监测

由于XMLHttpRequest对象是不能够通过页面刷新来传递数据的,因此很多时候无法准确判断数据是否已经发送给服务器,或者服务器是否已经返回了数据。为此,XMLHttpRequest对象定义了readyState属性来实时跟踪数据传输的状态。

20.6.1 跟踪状态

当XMLHttpRequest对象把HTTP请求发送到服务器端时,要经历几个过程,这时可以调用XMLHttpRequest的readyState属性来判断异步交互状态。

一旦当该属性发生变化时,即触发onreadystatechange事件,从而调用该事件绑定的处理函数(回调函数)。onreadystatechange是一种特殊的响应事件,它与HTTP传输紧密相关联,由readyState属性变化触发。readyState属性能够实时返回XMLHttpRequest请求的当前状态。借助readyState属性就可以准确判断请求和响应是否成功,readyState属性包括5个值,详细说明如表20-5所示。

表20-5 readyState属性值

如果readyState属性返回值为4,则说明响应完毕,那么就可以安全读取返回的数据。但是在实际开发中,开发人员习惯上把处理响应信息的代码封装在一个函数内,然后借用onreadystatechange事件来触发该函数。onreadystatechange定义当readyState属性值发生改变时将调用回调函数。

提示:HTTP状态码也可以处理请求/响应中可能发生的各种问题。例如,输入错误的URL请求而得到“404”错误码(表示该页面不存在)等。有关HTTP状态码比较多,这里就不再详细列表显示,用户可以参考本书光盘附赠的XMLHttp中文参考手册。

只有当状态码为200时,才表示HTTP响应顺利完成。在XMLHttpRequest对象中可以借助status属性获取当前的HTTP状态码。如果readyState属性值为4,且status(状态码)属性值为200,那么说明HTTP请求和响应过程顺利完成。

【示例】在20.5.2节示例的基础上在客户端页面中再定义一个函数handleStateChange(),用来监测HTTP状态,当整个通信顺利完成,则读取xmlhttp的响应文本信息。

然后,修改request()函数,为onreadystatechange事件注册处理函数:

上面的代码把读取响应数据的脚本放在函数handleStateChange()中,然后通过onreadystatechange事件来调用。

尽管onreadystatechange类似一个普通的事件处理函数,但是它也存在两点不同:

☑ 事件的type在IE中为load,而不是readystatechange。

☑ 该事件不会创建事件对象Event,但是在Safari浏览器中才为该事件定义一个事件对象。所以用户不要在事件处理函数中传递Event对象参数。

例如,下面代码是不能正常执行的:

不过,在使用Ajax进行异步交互时,onreadystatechange几乎没有必要访问事件对象。另外,onreadystatechange属性应该放置在调用send()方法之前。在XMLHttpRequest对象发送请求之前必须设置该属性,这样完成请求之后才能查看该属性。

20.6.2 中止请求

abort()方法允许中止正在进行的异步请求,不过很少这样做。在使用abort()方法前,应先清除onreadystatechange事件处理函数,因为IE和Mozilla在请求中止后也会激发这个事件处理函数,如果将onreadystatechange属性设置为null,则IE会发生异常,所以可以为它设置一个空函数,代码如下:

     Xmlhttp.Onreadystatechange=function(){}Xmlhttp.abort()

20.7 获取响应

当服务器端顺利完成响应之后,客户端就可以处理从服务器端返回的响应数据。返回的数据将保存在XMLHttpRequest对象的responseText、responseBody、responseStream或responseXML属性中。具体存储在哪个属性中,主要看服务器响应数据的格式而定。这4种属性说明如表20-6所示,它们都是只读属性。

表20-6 XMLHttpRequest对象响应信息属性

XMLHttpRequest对象可以根据服务器响应数据的格式来决定使用哪个属性容器存储返回的信息。一般常用的数据格式为文本格式(responseText)或XM格式(responseXML),对于二进制数据流可以使用responseStream属性存取。获取响应信息之后,还需要使用JavaScript脚本把它们转换为需要的样式显示出来。

XMLHttpRequest对象允许从服务器端响应任意格式的数据。但在实际应用中,一般都将格式约定为XML、HTML、JSON或其他某种纯文本格式。至于决定要使用哪种响应格式,用户可参考下面几条原则:

☑ 当向页面中添加大块数据时,选择HTML格式会比较省事。

☑ 如果需要团队协作开发,且项目庞杂,选择XML格式会更容易协调。

☑ 如果要检索复杂的响应数据,且结构复杂,那么选择JSON格式会比较方便。

20.7.1 XML

在异步交互中,XML是使用最广泛的数据格式。因为XML文档可以被很多编程语言支持,而且开发人员可以使用比较熟悉的DOM模型来解析数据,其缺点在于,服务器的响应和解析XML数据的脚本可能变得相当冗长,查找数据时不得不遍历每个节点。

【示例1】在服务器端创建一个简单的XML文档(XML_server.xml):

     <?xml version="1.0" encoding="utf-8"?><the>XML 数据</the >

然后在客户端进行如下请求(XML_main.html):

在上面的代码中使用XML DOM提供的getElementsByTagName()方法获取the节点,然后再定位第一个the节点的子节点内容。此时如果继续使用responseText属性来读取数据,则会返回XML源代码字符串,如下所示:

     <?xml version="1.0" encoding="utf-8"?><the>XML 数据</the >

【示例2】也可以使用服务器端脚本生成XML文档结构。例如,以ASP脚本生成上面的服务器端响应信息:

提示:对于XML文档数据来说,第一行必须是<?xml version="1.0" encoding="utf-8"?>,该行命令表示输出的数据为XML格式文档,同时标识了XML文档的版本和字符编码。为了能够兼容IE和FF等浏览器,能让不同浏览器都可以识别XML文档,还应该为响应信息定义XML文本类型。最后根据XML语法规范编写文档的信息结构。然后,使用上面的示例代码请求该服务器端脚本文件,同样能够显示元信息字符串"XML数据"。

20.7.2 HTML

设计响应信息为HTML字符串是一种常用的方法,这样在客户端就可以直接使用innerHTML属性把获取的字符串插入到网页中。

【示例】在服务器端设计响应信息为HTML结构代码(HTML_server.html):

然后在客户端可以这样来接收响应信息(HTML_main.html):

在某些情况下,HTML字符串可能为客户端解析响应信息节省了一些JavaScript脚本,但是也带来了一些问题:

☑ 响应信息中包含大量无用的字符,响应数据会变得很臃肿。因为HTML标记不含有信息,完全可以把它们放置在客户端由JavaScript脚本负责生成。

☑ 响应信息中包含的HTML结构无法有效利用,对于JavaScript脚本来说,它们仅仅是一堆字符串。同时结构和信息混合在一起,也不符合标准设计原则。

20.7.3 JavaScript

可以设计响应信息为JavaScript代码,这里的代码与JSON数据不同,它是可执行的命令或脚本,一般不用来包含丰富的信息。

【示例】在服务器端请求文件中包含下面一个函数(Code_server.js):

然后在客户端执行下面的请求:

在转换时应在字符串前后附加两个小括号:一个是包含函数结构体的,一个是表示调用函数的。

一般很少使用JavaScript代码作为响应信息的格式,因为它不能够传递更丰富的信息,同时JavaScript脚本极易引发安全隐患。

20.7.4 JSON

设计响应格式为JSON是一个不错的选择,因为JSON不仅包含丰富的信息,而且数据读取和转换也比较容易,服务器端只需负责响应信息,而对响应信息的解释工作则由客户端JavaScript脚本负责完成。与XML相比,它更容易融于JavaScript脚本中。

从本质上分析,JSON数据实际上就是一个JavaScript对象或数组。不过,一般响应的JSON数据多为简单的JavaScript对象。

或:

通过XMLHttpRequest对象的responseText属性获取返回的JSON数据字符串,然后可以使用eval()方法将其解析为本地JavaScript对象,从该对象中再读取任何想要的信息。

【示例】本实例将返回的JSON对象字符串转换为本地对象,然后读取其中包含的属性值(JSON_main.html):

在转换对象时,应该在JSON对象字符串外面包含小括号运算符,表示调用对象的意思。如果是数组,则可以这样读取(JSON_main1.html):

提示:eval()方法在解析JSON字符串时存在安全隐患。如果JSON字符串中包含恶意代码,在调用回调函数时可能会被执行。

解决方法:

使用一种能够识别有效JSON语法的解析程序,当解析程序一旦匹配到JSON字符串中包含不规范的对象,会直接中断或者不执行其中的恶意代码。用户可以访问http://www.json.org/json2.js免费下载JavaScript版本的解析程序。不过如果确信所响应的JSON字符串是安全的,没有被人恶意攻击,那么可以使用eval()方法解析JSON字符串。

20.7.5 Text

对于简短的信息,有必要使用纯文本格式进行响应。其缺点是,纯文本信息在响应时很容易丢失,且没有办法检测信息的完整性。因为缺少元数据,元数据都以数据包的形式进行发送,不容易丢失。

【示例】服务器端响应信息为字符串"true",则可以在客户端这样设计:

20.7.6 获取头部消息

每个HTTP请求和响应的头部都会包含一组消息,对于开发人员来说,获取这些信息具有重要的参考价值。为此,XMLHttpRequest对象提供了两个方法。

☑ getAllResponseHeaders():获取响应的所有HTTP头信息。

☑ getResponseHeader():从响应信息中获取指定的HTTP头信息。

【示例1】本示例将获取HTTP响应的所有头部消息:

【示例2】下面是一个返回的头部消息示例,具体到不同的环境和浏览器,返回的信息会略有不同:

     X-Powered-By: ASP.NETContent-Type: text/plainETag:"0b76f78d2b8c91:8e7"Content-Length: 2Last-Modified: Thu, 09 Apr 2016 05:17:26 GMT

如果要获取指定的某个首部消息,可以使用getResponseHeader()方法,参数为获取首部的名称。例如,获取Content-Type首部的值,则可以这样设计:

     alert(x.getResponseHeader("Content-Type"));

除了可以获取这些头部信息外,还可以使用setRequestHeader()方法在发送请求中设置各种首部信息。例如:

     xmlHttp.setRequestHeader("name","css8");xmlHttp.setRequestHeader("level","2");

这样,服务器端就可以接收这些自定义首部信息,并根据这些信息提供特殊的服务或功能。

20.8 案例实战

Ajax技术扩展了前端开发人员的设计空间,从而设计能够在静态的页面中提供更加强大的交互功能,这意味着用户可以在不中断用户体验的同时,修改静态页面的行为习惯,并为用户提供更多的浏览体验和交互情趣。

20.8.1 封装异步交互

从根本上来说,每次进行Ajax请求都没有什么区别,但是服务器却返回不同的数据。下面尝试把上面各节所学的知识汇总在一起,定义一个通用函数,这样就不用关心Ajax技术本身了,而将更多的精力用在思考如何去呈现数据上,并设计美轮美奂的交互效果。封装异步请求的函数如下:

20.8.2 设计动态响应的Tab面板

Tab面板是常见的一种交互效果,所显示的信息多是静态的。本案例设计:当鼠标移动到不同的Tab选项卡时,将触发事件处理函数,向服务器发出异步请求,并把服务器响应的信息呈现在该Tab面板中,演示效果如图20-5所示。

图20-5 动态响应的Tab面板演示效果

【操作步骤】

第1步,新建网页文档,保存为index.html。

第2步,设计Tab面板结构,页面基本结构如下:

服务器端的信息处理可以根据服务器技术的不同分别进行设计,但是在动手之前,用户应该先设计好服务器端接口,包括请求参数和响应信息的格式。这个问题先放在最后进行说明,下面重点讲解异步请求过程的实现。

第3步,异步请求过程也要先设计好接口问题(即请求的URL)、发送参数的传递方式,以及回调函数的设计。在设计回调函数时,应该与服务器端响应信息类型和结构相协调一致。设计思路如下:

☑ 异步请求接口

▶ 参数:以GET方法发送请求,参数名为n,参数值包含选项卡的序号,如1、2。

▶ 回调函数:把响应的XML数据转换为HTML,并插入到Tab面板容器中。

☑ 服务器端响应接口

▶ 参数:获取查询字符串,参数名为n,根据参数值在数据库中查询不同类型的词条。

▶ 响应信息:以XML格式响应信息,XML文档结构如下。

第4步,在index.html页面头部插入一个<script type="text/JavaScript">标签,在其中先定义一个函数,该函数是为每个选项卡绑定的事件处理函数,当鼠标移过Tab选项卡将被触发。

在这个函数中,主要设置了两个必需的参数:URL和回调函数,并调用20.8.1节讲解的封装异步请求函数。函数mouseover()的参数n表示选项卡的序号,从1开始。

第5步,在页面初始化事件中,为每个选项卡的li元素注册该函数为事件处理函数,同时默认显示第一个选项卡中的数据:

第6步,下面介绍服务器端如何响应信息,以及客户端又如何读取并显示这些信息。假设服务器响应信息为XML格式,则在客户端可以这样设计回调函数所包含的Tab信息更新函数。这个函数有两点需要用户注意。

☑ 要注意XMLHttpRequest对象参数传递,否则在多层函数嵌套中可能会出现找不到对象的现象。

☑ 借助XMLHttpRequest对象的readyState属性,动态显示数据的交互过程,使页面设计更友好。

第7步,在updatePage()函数中包含一个toHTML()函数,该函数专门负责把服务器端响应的XML数据转换为HTML格式信息:

第8步,设计服务器端如何动态生成XML数据。本案例服务器端使用ASP技术,将根据客户端请求的参数来查询Access数据库中的数据,则整个请求文件的代码如下:

在生成XML文档时,应该注意以下几个问题:

☑ XML文档结构有着严格的要求,第一行必须是XML文档的命令行。XML文档中根节点只有一个,且结构嵌套必须对称。

☑ XML字符编码应该与客户端页面编码相一致,同时应注意与服务器端脚本的编码也保持一致。

☑ 在生成XML文档时,应该定义文档类型(如text/xml)。

20.8.3 使用灯标

有时可以不关心接收数据,只要将数据发送给服务器即可,这时有两种可选的技术方案:XMLHttpRequest(XHR)和灯标。

灯标与动态脚本标签插入非常类似。JavaScript创建一个新的Image对象,将src设置为服务器上一个脚本文件的URL,该URL包含通过GET格式传回的键值对数据。注意,这里并没有创建img元素或将它们插入到DOM中。

【示例1】下面的代码利用灯标技术向服务器端发送两个参数信息。

     var url='/status_tracker.asp';var params=['step=2', 'time=1248027314'];(new Image()).src=url+'?'+params.join('&');

服务器得到此数据并保存下来,不必向客户端返回什么,因此没有实际的图像显示。这是将信息发回服务器的最有效方法,开销很小,而且任何服务器端错误都不会影响客户端。

简单的图像灯标不能发送POST数据,所以应将URL长度限制在一个相当小的字符数量上。当然也可以用非常有限的方法接收返回数据,可以监听Image对象的load事件,判断服务器端是否成功接收了数据。还可以检查服务器返回图片的宽度和高度(如果返回了一张图片),并用这些数字通知服务器的状态,例如,宽度为1表示成功,2表示重试等。

【示例2】如果不需要为此响应返回数据,那么应当发送一个204 No Content响应代码,表示无消息正文,从而阻止客户端继续等待永远不会到来的消息体。

灯标是向服务器回送数据最快和最有效的方法。服务器根本不需要发回任何响应正文,所以不必担心客户端下载数据。使用灯标的唯一缺点是接收到的响应类型是受限的。如果需要向客户端返回大量数据,那么建议使用XHR。如果只关心将数据发送到服务器端,那么使用图像灯标。

第20章 JavaScript通信相关推荐

  1. 《HTML+CSS+JavaScript》之第20章 超链接样式

    <HTML+CSS+JavaScript>之第20章 超链接样式 20.1 超链接伪类 20.1.1 超链接伪类简介 20.1.2 深入了解超链接伪类 20.2 深入了解hover 20. ...

  2. React-Native系列Android——Native与Javascript通信原理(一)

    React-Native最核心的是Native与Javascript之间的通信,并且是双向通信.Native层到Javascript层,Javascript层到Native层.虽说是两个方向,但实现上 ...

  3. Javascript第六章JavaScript字面量加数组创建对象第三课

    Javascript第六章JavaScript用new创建对象第一课 https://blog.csdn.net/qq_30225725/article/details/89304586 Javasc ...

  4. 《Python编程无师自通》第20章 融会贯通

    第20章 融会贯通 "神话和传说的魔力在我们这一代成真.只要在键盘上敲下正确的咒语,显示屏就像是活了过来,里面都是以前不可能存在或发生的事情." --费德里克·布鲁克斯(Frede ...

  5. 《JavaScript权威指南第7版》第11章 JavaScript标准库

    第11章 JavaScript标准库 11.1 Set和Map 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMap和WeakSet 11.2 类型数组和二进制数据 11.2. ...

  6. 第三章 隐藏通信隧道技术

    第三章 隐藏通信隧道技术 3.1 隐藏通信隧道基础知识 3.1.1 隐藏通信隧道概述 什么是隧道? 在实际的网络中,通常会通过各种边界设备.软/硬件防火墙甚至入侵检测系统来检查对外连接情况,如果发现异 ...

  7. JavaScript权威指南 第11章JavaScript标准库

    JavaScript权威指南 第11章JavaScript标准库 第11章 JavaScript标准库 11.1 集合与映射 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMa ...

  8. 【正点原子FPGA连载】第十四章 串口通信实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  9. 5G NR标准: 第20章 5G的演进

    第20章 5G的演进 NR 的第一个版本,第 15 版,侧重于对 eMBB 的基本支持,在某种程度上,URLLC.1 如前几章所述,第 15 版是为即将发布的 NR 未来发展构建的基础 . NR 演进 ...

最新文章

  1. python语言入门m-Python学习基础篇 -1
  2. 都说了多少遍,不要再学 JSP 了!
  3. 音频处理四:(音频的分帧)
  4. rman全备时,配置项如何设置?
  5. VSTO之旅系列(五):创建Outlook解决方案
  6. Delphi中线程类TThread实现多线程编程2---事件、临界区、Synchronize、WaitFor……
  7. mysql有没有模式,关于sql:没有数据的MySql导出模式
  8. Thrift RPC实战(七) 基于zookeeper和thrift的RPC服务发布订阅
  9. NTFS文件系统详细分析
  10. 残差、方差、偏差、MSE均方误差、Bagging、Boosting、过拟合欠拟合和交叉验证
  11. tf.maximum
  12. oracle基础|什么是数据库操作语言|什么是DDL、DML、DCL
  13. 亚马逊云助手小程序来啦!
  14. 自制迷宫小游戏 :O 的冒险
  15. 你们知道官网购买服务器可以返佣吗
  16. 利用Python编写脚本批量下载公众号中的音频
  17. 完美解决 iOS 中只旋转自己想要旋转的屏幕
  18. 金庸小说人物知识图谱构建——以《雪山飞狐》为例
  19. 魏永征《向媒介侵权讨说法:媒介侵权法律问题》
  20. 什么是云效,云原生时代一站式DevOps平台

热门文章

  1. 计算机网络笔记:IPV6
  2. 猿人学题库第二题——简易动态js加密解析
  3. MySQL日志序列号 - LSN
  4. 序列模型与注意力机制
  5. vue自适应带圆圈的进度条实现#根据数量占比计算进度条长度#颜色可控
  6. 计算机相关理论和实践知识题,计算机上机考试模拟考试习题.doc
  7. linux中ls l wc,linux wc命令有什么用
  8. PayPal(v2)扣款(用户创建订单、授权、扣款、退款)模式
  9. 记录安装、配置并入门使用appium的过程
  10. 将jsp变为html