写在本章内容前:
第十五章:事件处理 涉及到到较多的文字篇幅,介于个人精力问题,暂不更新。主要包含的内容有事件类型、注册事件处理程序、事件处理程序的调用、文档加载事件、鼠标事件、鼠标滚轮事件、拖放事件、文本事件、键盘事件等9块内容。感兴趣的朋友可以留言传内容PDF。如果不着急的话,后期可能更新。敬请关注。
超文本传输协议(HTTP)规定web浏览器如何从web服务器获取文档和向web服务器发送表单内容,以及web服务器如何响应这些请求和提交。web浏览器会处理大量的HTTP。通常,HTTP并不在脚本的控制下,只是当用户单击链接、提交表单和输入URL时才发送。
但是,用javascript代码操纵HTTP是可行的。当脚本设置window对象的location属性或调用表单对象的submit()方法时,都会初始化HTTP请求。在这种情况下,浏览器会从新加载页面。这种用脚本控制HTTP的方法在多框架页面中非常有用,但这并非我们讨论的主题。相反,这章讨论在没有导致web浏览器重新加载任何窗口或窗体内容的情况下,脚本如何实现浏览器与服务器之间的通信。
术语Ajax描述了一种主要使用脚本操作HTTP的web应用构架。(Ajax是Asynchronous Javascript and xml的缩写,这个术语由jesse James Carrett创造,最早出现于2005年2月它发布的文章。“Ajax”曾经是一个流行多年的术语,现在它只不过是一个有用的术语,来描述脚本操纵HTTP请求的web应用构架)。Ajax应用的主要特点是使用脚本操作HTTP和web服务器进行数据交换,不会导致页面重载。避免页面重载(这是web初期的标准做法)的能力能使web应用感觉更像传统的桌面应用。web可以使用Ajax技术把用户的交互记录数据记录到服务器中;也可以是简单的显示页面,之后按需加载额外的数据和页面组件来提示应用的启动时间。
Comet是和使用脚本操作HTTP的web应用构架相关的术语(Comet这个名字是Alex Russell在2006年3月创造,这个名字可能是对Ajax开了个玩笑,Comet和Ajax都是美国的洗涤日用品牌)。在某种意义上,Comet和Ajax相反,在Comet中,web服务器发起通信并异步发送到消息客户端。如果web应用需要相应服务器发送消息,则它会使用Ajax技术发送或请求数据。在Ajax中,客户端从服务器“拉”数据。在Comet中,服务端向客户端“推”数据。Comet还包括其他名词,如:“服务器推”,“Ajax推”,“HTTP流”。
实现Ajax和Comet的方式有很多种,而这些底层的实现有时候称为传输协议(transport)。例如:<IMG>元素有一个src属性。当脚本设置这个属性为url时,浏览器发起的HTTP请求会从这个URL下载图片。因此脚本通过设置<img>元素的src属性,且把信息图片URL的查询字符串部分,就把能经过编码的信息传递给web服务器。web服务器实际上必须返回某个图片作为请求结果,但它一定要不可可见。例如一个1*1像素的透明图片(这种类型的图片也叫网页信标(web bug)当网页信标不是与当前网页服务器而是其它服务器交流信息时,会担心隐私泄露。这种第三方的网页信标方式常用于统计点击数和网站流量分析)。
<img>元素无法实现完整的的Ajax传输协议,因为数据交换是单向的:客户端能发送数据到服务器,但服务器的响应一直是张图片导致客户端无法从中获取提取信息。然而<iframe>元素更加强大,为了把<iframe>作为Ajax传输协议使用,脚本首先要把发送给web服务器的信息编码到URL中,然后设置<iframe>的src属性为该URL。服务器创建一个包含响应内容的HTML文档。并把它返回给web浏览器。并且在<iframe>中显示它。<iframe>需要对用户不可见。可以使用CSS隐藏它。脚本能遍历<iframe>的文档对象来读取服务端的响应,注意,这种方法受限于11.6.ii介绍的同源策略问题。
实际上,<script>元素的src属性能设置URL并发起HTTP GET请求,使用<script>元素实现脚本操纵HTTP是非常吸引人的。因为它们可以跨域通信并不受限于同源策略。通常,使用<script>的Ajax传输协议时,服务器的响应采用JSON(见6章9节)的数据格式,当知心脚本时,javascript解析器也能自动将其“解码”。由于它使用JSON数据格式,因此这种Ajax传输协议也叫“JSONP”。
虽然在<iframe>和<script>传输协议上能实现AJAX技术,但通常还有更简单的方式,一段时间来,所有的浏览器都支持xmlhttpRuquest对象,它定义了用脚本操作HTTP的API。除了常用的GET请求,这个API还包含实现POST请求能力,同时它能用文本或Document对象的形式返回服务器响应。虽然它的名字叫XMLHttPRequest API,但并没限定只能使用XML文档,他能获取任意类型的文本文档。本章第1节涵盖XMLHttpRequestAPI和本章的大部分。
本章的大部分Ajax示例都将使用XMLHttpRequest对象实现协议(第1节)方案,我们也将在本章第2节演示如何基于<script>的传输协议。因为<script>有规避同源限制的能力。
XML是可选的
“Ajax”中的X表示XML。这个HTTP(XMLHttpRquest)主要客户端API在其名字中突出了XML,并且我们在后面将看到XMLHttpRequest对象的一个重要属性叫responseXML。它看起来像说明XML是脚本操纵HTTP的重要部分,但实际上不是。这些名字只是XML流行时的遗迹。当然AJax吉祥能和XML文档一起工作。但使用XML只是一种选择。实际上很少使用。XMLHttpRequest规范列出了这个令人困惑的名字的不足之处:
对象名XMLHttpRequest是为了兼容web,虽然这个名字的每个部分都可能造成误导。首先,这个对象支持包括XML在内的任何基于文本的格式。其次,它能用于HTTP和HTTPS请求(一些实现支持除了HTTP和HTTPS之外的协议,但规范不包括这些功能)。最后它支持的请求是一个广义的概念,指定是对定义的HTTP方法的设计HTTP请求或响应的所有活动。
Comet传输协议比Ajax更精妙,但需要客户端和服务器建立(必要时重新建立)连接。同时要保存服务器连接处于打开状态。这样才能发送异步信息。隐藏的<irrame>能像Comet传输协议一样有用。例如:服务器以<iframe>中执行的<script>元素的形式发生每条消息。实现Comet的一种更可靠的跨平台方案是客户端简历一个服务器连接(使用Ajax协议),同时服务器包装这个连接打开直到它需要推送一条信息,服务器每发送一个信息就关闭这个连接。这样就可以确保客户端正确接收到消息。处理该消息之后,客户端马上为后续的消息推送建立一个新连接。
实现可靠的跨平台Comet传输协议是非常有挑战性的,所以大部分使用Comet构架的web应用开发者依赖像Dojo这样的web框架中的传输协议。HTML5相关草案的Server-Sent事件,它用EventSource对象的形式定义了简单的Comet API。本章第3节涵盖EventSoure API并且演示了一个使用XMLHttpRequest显示的简单模拟示例。
在Ajax和Comet之上构建更高的通信协议是可行的。例如,这些客户端/服务器技术可以用作RPC(Remote Procedure Call,远程过程调用)机制或发布/订阅事件系统基础。
本章不会介绍更高的协议,我们的重点在能使Ajax和Comet可用的API上。
1.使用XMLHttpRequest
浏览器在XMLHttpRequest类上定义了它们的HTTP API。这个类的每个实例都表示一个独立的请求/响应对。并且这个对象的属性和方法允许指定请求细节和提取响应数据。很多年前web浏览器就开始支持XMLHttpRequest,并且其API已经到了W3C的最后制定标准的最后阶段。同时W3C在制定“2级XMLHttpRequest”的标准草案。本节涵盖XMLHttpRequest核心API。也包括当前至少被两款浏览器支持的2级XMLHttpRequest标准草案(我们称为XHR2)。
当然,使用这个HTTP API做的第一件事就是实例化XMLHttpRequest对象:
var request = new XMLHttpRequest();
你也可以重用已存在的XMLHttpRequest,但注意这将会终止之前通过该对象挂起的任何请求。
IE6中的XMLHttpRequest
微软最早把XMLHttpRequest对象引入到IE5中,并且在IE5和6中只是一个Active对象。IE7之前的版本不支持非标准的XMLHttpRequest()构造函数,但能像以下来模拟解决:
//ie5和i6模拟XMLHttpRequest()构造函数 if (window.XMLHttpRequest === undefined) { window.XMLHttpRequest = function() { try { //如果可用,则使用Active对象的最新版本 return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) { try { //否则回退早的版本 return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) { //否则,抛出错误 throw new Error("XMLHttpRequest is not supported"); } } }; }
一个HTTP请求由4个部分组成:
服务器返回的HTTP请求响应包含3个部分:
接下来两节我们将会展示如何设置HTTP请求的每个部分和如何查询HTTP响应的每个部分。随后的核心章节会涵盖更多的专门议题。
HTTP的基础请求/响应构架非常简单并易用使用。但在实践中会有各种各样的带来复杂的问题:客户端和服务器交换cookie,服务器重定向浏览器到其它服务器,缓存某些资源而剩下的不缓存,某些客户端通过代理服务器发送所有的请求等。
XMLHttpRequest不是协议级的HTTP API,而是浏览器级的API,浏览器需要考虑cookie、重定向、缓存和代理,但代码只须担心请求和响应。
XMLHttpRequest和本地文件
网页中可以使用相对URL意味这我们可以使用本地文件系统来开发和测试HTML,来避免不必要的服务器端部署。然而在师院XMLHttpRequest进行Ajax编程时,这是不行的。XMLHttpRequest用于同HTTP和HTTPS协议一起工作,理论上,它能够同样像FTP这样的协议一起工作,比如请求方法和响应状态码等API都是HTTP特有的。如果从本地加载网页。那么该页面中的脚本无法通过相对的URL使用XMLHttpRequest,因为这些URL将相对于file://URL而不是http:// URL。而同源策略通常会阻止使用绝对的HTTP:// URL(见本小节的iiiiii小节)。结果是当使用XMLHttpRequest时,为了测试他们通常把文件上传到web服务器(或运行一个本地服务器)。
i.指定请求
创建XMLHttpRequest对象之后,发起HTTP请求下一步是调用XMLHttpRequest对象的open()方法去指定这个请求的两个必须部分:方法和URL。
request.open("GET",//开始一个HTTP GET请求 "data.csv;") //URL的内容
open()的第一个参数指定HTTP方法或动作。这个字符串不区分大小写,但通常大家使用大写来匹配HTTP协议。“GET”和"POST"方法是广泛支持的。“GET”用于常规请求,它适用于当URL完全指定请求资源,当请求对服务器没有任何副作用以及当服务器响应是可缓存的。“POST”方法常用于HTML表单。它在请求主体中包含额外数据(表单数据),且这些数据常存储到服务器上的数据库中(副作用)。相同的URL重复“POST”请求可能从服务器得到的响应可能不同,同时不应该缓存使用这个方法的请求。
除了GET和POST之外 ,XMLHttpRquest规范也把DELETE,HEAD,OPTIONS和PUT作为open() 第一个参数。(HTTP CONNTECT TRACE TRACK因为安全风险已经被明确禁止)。旧的浏览器并不支持这些方法,但至少“HEAD”得到广泛支持,本章有例子演示如何使用它。
open()第二个参数是URL。它是请求的主题。这是相对于文档的URL,这个文档包含调用open()的脚本。如果指定绝对URL、协议、主机和端口通常必须匹配所在文档的对于内容:跨域请求通常会报错(但是在服务器明确允许跨域时,2级XMLHttpRequest规范会允许它。第iiiiii小节)。
如果有请求头的话,请求进程的下个步奏是设置它。例如,POST请求需要“Content-Type”头指定请求主题的MIME类型。
request.setRequestHeader("Content-Type", "text/plain");
如果相同的头调用setRequestHeader()多次,新值不会取代之前指定的值,相反,HTTP请求将包含这个头的多个副本或这个头将指定多个值。
你不能自己指定“Content-Length”、“Date”、“Referer”或“User-Agent”头,XMLHttpRequest将自动添加这些头防止伪造它们。类似地,XMLHttpRequest对象自动处理cookie、连接时间、字符集和编码判断,所以你无法向setRequestHeader()传递这些头。
Accept-Charset | Content-Transfer-Encoding | TE |
Accepet-Encoding | Date | Trailer |
Connection | Expect | Transfer-Encoding |
Content-length | Host | Upgrad |
cookie | Keep-Alive | User-Agent |
cookie2 | Referer | Via |
你能为请求指定“Authorization”头,但通常不需要这么做。如果请求一个受密码保护的URL,把用户名和密码作为第4个和第5个参数传递给open()可选的第三个参数。可选的用户名和密码参数会在第4部分介绍。
使用XMLHttpRequest发起HTTP请求的最后一步是 指可选的请求主体并向服务器发送它。使用send()方法像如下这样做:
request.send(null);
GET请求绝对没有主体,所有应该传递null或省略这个参数。POST请求通常拥有主体,同事它应该配置使用setRequestHeader()指定的“Content-Type”头。
顺序问题
HTTP请求的各部分有指定顺序:请求方法和URL首先到达,然后是请求头,最后是请求主体。XMLHTTPRequest实现通常调用send()方法开始启动网络。但XMLHTTPRequest API的设计似乎使每个方法都写入网络流。这意味这调用XMLHTTPRequest方法的顺序必须匹配HTTP请求的构架。例如setRequestHeader()方法的调用必须在调用open()之前但在调用send()之后。否则它将抛出异常。
下面的例子调用了目前我们介绍的所有XMLHttpRequest方法。它用POST方法发送文本
新闻热点
疑难解答