第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等基本文档结构元素平行使用&#x