<6>脚本化http( XMLHttpRequest)

[b]六、脚本化http( XMLHttpRequest)[/b]
超文本传输协议规定web浏览器如何从web服务器获取文档和向web服务器提交表单内容,以及web服务器如何应如何响应这些请求和提交。[b]Web浏览器会处理大量http。[/b]通常,http并不在脚本的控制下,只是当用户单击链接,提交表单和输入url时才发生。

[b][color=red]Ajax[/color]描述了一种主要使用脚本操纵http和web服务器进行数据交换,不会导致页面重载[/b]。避免页面重载的能力使得web应用感觉更像传统的桌面应用。Web应用可以使用Ajax技术把用户的交互数据记录到服务器中,也可以开始只显示简单页面,之后按需要加载额外的数据和页面组件来提升应用的启动时间。

Comet是使用脚本操纵http的web应用架构相关的术语。某种意义上,comet和ajax相反。在Comet中,web服务器发起通信并异步发送消息到客户端。[b]在Ajax中,客户端从服务器拉数据,而在Comet中,服务器向客户端推数据。[/b]

[b]<script>元素的src属性能设置url并发起http get请求。[/b]使用<script>元素实现脚本操纵http是非常吸引人的,因为他们可以[color=red]跨域通信[/color]二不受限制于同源策略。通常,使用基于<script>的ajax传输协议时,服务器的响应采用json编码的数据格式,当执行脚本时,javascript解析器能自动将其解码。由于它使用JSON数据格式,因此这种Ajax传输协议也叫做[color=red][b]“JSONP”[/b][/color].
虽然在<iframe>和<script>传输协议之上能实现Ajax技术,但通常还有更简单的方式。一段时间以来,所有浏览器都支持[b]XMLHttpRequest[/b]对象,它定义了用脚本操纵HTTP的API。除了常用的GET请求,还包含实现POST,HEAD等请求的能力,同时他能用文本或Document对象的形式返回服务器的响应。虽然它名字叫XMLHttpRequest API,但并没有限制只能使用xml文档,它能获取任何类型的文本文档。

[b]使用XMLHttpRequest[/b]

[b]1. 指定请求[/b]
浏览器在XMLHttpRequest类上定义了他们的HTTP API。这个类的每个实例都表示一个独立的请求/响应对,并且这个对象的属性和方法允许指定请求细节和提取响应数据。

[b]Step0:创建对象 request[/b]
使用这个HTTP API必须做的第一件事就是实例化XMLHttpRequest对象:
Var request = new XMLHttpRequest();

记住,[b]每个实例表示一个独立的请求响应对[/b],如果重用已存在的XMLHttpRequest,将会终止之前这个对象之前的任何请求。

[b]Step1:指定请求 open()[/b]
创建XMLHttpRequest对象之后,发起HTTP请求的下一步是调用XMLHttpRequest对象的open()方法去指定这个请求的两个必须部分:方法和url。
Request.open(“GET”,       // 开始一个http get请求
“data.csv”); // url,请求的地址

Open()的[b]第一个参数[/b]是指定http方法会或动作。这个字符串不区分大小写,但通常用大写字母匹配http协议。“get”和“post”方法是得到广泛支持的。Get用于常规请求,适合于当url完全指定请求资源,当请求对服务器[b]没有任何副作用[/b]以及当服务器的响应是可缓存的。POST方法常用语html表单,它在请求主体中包含额外的数据(表单数据),且这些数据常存储到服务器中([b]副作用[/b])。相同url的重复post请求从服务器得到的响应可能不同,同时不应该缓存使用这个方法的缓存。
除了get和post之外,XMLHttpRequest规范也允许把delete,head,options和put作为open()的第一个参数。

Open的[b]第二个参数[/b]是url,它是请求的主体。这是相对于包含open()脚本的document的url。如果指定绝对url,协议,主机和端口号通常必须匹配所在文档的对应内容,[b]跨域的请求通常会报错。[/b]

Open的[b]第三个参数[/b]是布尔值,代表请求是同步还是异步,默认为true,是异步的,设为false代表同步的。设成异步的就不要给XMLHttpRequest设置readystatechange事件响应函数了,直接可以取得响应消息。但是,客户端javascript是单线程的,这样会导致阻塞,整个浏览器UI冻结,谨慎使用。


[b]Step3:设置请求头 ,setRequestHeader()[/b]
如果有请求头的话,请求进程的下一步就是设置它,如post请求需要“Content-Type”指定请求主体的MIME类型:
Request.setRequestHeader(“Content-Type”, “text/plain”);
如果对相同的头调用setRequestHeader()多次,新值不会取代之前指定的值,相反,http请求将包含这个头的多个副本或这个头将指定多个值。

不能自己指定“Content-Length”,”Date”,”Refer”或”User-Agent”头,XMLHttpRequest将自己添加这些头防止伪造他们。类似地,XMLHttpRequest对象自动处理cookie,连接时间,字符集和编码判断,程序员无法向setRequestHeader()传递这些头:
[img]http://dl2.iteye.com/upload/attachment/0091/4604/7c7d8562-c73d-3c16-b8d2-cf9a531eab54.bmp[/img]


如果请求一个受密码保护的url,把用户名和密码作为[b]第四个和第五个参数[/b]传递给open。

[b]Step4: 发送请求 send()[/b]
使用XMLHttpRequest发起http请求的最后一步是指定可选的请求主体并向服务器发送它。
Request.send(null);
Get请求绝对没有主体。所以应该传递null或省略这个参数。
POST请求通常拥有主体,同时它应该匹配用setRequestHeader指定的“Content-Type”头。

[b]顺序问题:[/b]
[u]http请求的各部分有指定顺序,请求方法和url先到达,然后是请求头,最后是请求主体。XMLHttpRequest实现通常直到调用send()方法才开始启动网络,但顺序必须匹配,如setRequestHeader必须在open之后和send之前,否则将抛出异常。[/u]

[b]2. 取得响应[/b]
一个完整的http响应由状态码,响应头集合和响应主体责成,这些都可以通过XMLHttpRequest对象的属性和方法获得。
1) status和statusText属性以数字和文本的形式返回http状态码。
2) 使用getResponseHeader()和getAllResponseHeaders()能查询响应头。
3) 响应主体可以从responseText属性中得到文本形式的,从responseXML属性中得到Document形式的(它实际对XHtml和xml文档都有效)。

XMLHttpRequest通常异步使用,发送请求后,send()方法立即返回,知道响应返回勤勉列出的响应方法和属性才有效。为了在响应准备就绪时得到通知,必须监听XMLHttpRequest对象上的readystatechange事件,对应readyState属性的变化。
readyState是一个整数,指定了http请求的状态,为4时代表响应完全返回。

为了监听[b]readystatechange[/b]事件,把事件处理函数设置为XMLHttpRequest对象的[b]onreadystatechange[/b]属性。

[img]http://dl2.iteye.com/upload/attachment/0091/4606/37bb61e6-3659-3a91-a7d1-40b316f8c3f5.bmp[/img]

[b]1. 响应解码[/b]
前面我们假设服务器使用像“text/plain”,”text/html”或“text/css”这样的MIME类型发送文本响应,然后我们使用[b]XMLHttpRequest对象的responseText属性[/b]得到它。

但是还有其他方式来处理服务器响应。如果服务器发送xml或xhtml文档作为响应,能通过[b]responseXml属性[/b]获得一个解析形式的xml文档。这个属性的值是一个document对象,可以使用前面介绍的技术搜索和遍历操作。

如果服务器想发送诸如对象或数组这样的结构化数据作为响应,应该传输[b]JSON编码[/b](“application/json”)的字符串数据。接收它时,可以把responseText属性传递给JSON.parse()。

如果期望响应的类型是”application/javascript”或”text/javascript”,这种情况下不需要使用XMLHttpRequest对象,因为<script>本身完全可以实现加载并执行脚本。而且,[b]<script>可以发起跨域http请求,而XMLHttpRequest API则禁止。[/b]

Web服务器端通常使用二进制数据(如图片,文件)响应http请求,responseText属性只能用于文本。目前还没有一个统一各浏览器处理的成熟方法,可以参考:[url]http://stackoverflow.com/questions/4376657/is-there-any-way-to-send-binary-data-with-xmlhttprequest-object[/url]

服务器响应的正常解码是假设服务器为这个响应发送了“Content-Type”头和正确的MIME类型。

[b]2. 编码请求主体[/b]
HTTP POST请求包括一个请求主体,它包含客户端传递给服务器的数据。

[b]3.1 表单编码的请求[/b]
当用户提交html表单时,表单中的数据(每个表单元素的名字和值,因此也要求表单元素必须有name和value属性)编码到一个字符串中并随请求发送。默认情况下,html表单通过post方法发送给服务器,而编码后的表单数据则用作请求主体。编码方法是:对每个表单元素的名字和值执行普通的url编码(使用十六进制转移码替换特殊字符),使用等号把编码后的名字和值分开,并使用”&”分开名/值对。如:
Find=pizza&zipcode=2323&radius=1km

表单编码格式有一个正式的MIME类型:
application/x-www-form-urlencoded
当使用post方法提交这种顺序的表单数据时,必须设置“Content-Type”为这个值。

表单数据同样可以通过GET请求来提交,当知识为了执行只读查询,get请求比post请求更合适。

[b]3.2 JSON编码的请求[/b]
Html form并不是http提交的必须类型,现在作为web交换格式的JSON已经得到普及,可以使用JSON.stringify()对请求主体编码。

[img]http://dl2.iteye.com/upload/attachment/0091/4608/4a26ad3c-a32f-3065-93b2-4e21cf312dfe.bmp[/img]

[b]3.3 Multipart/form-data请求[/b]
当html表单同时包含文件上传元素和其他元素时,浏览器不能使用普通的表单编码而必须使用称为”multipart/form-data”的特殊content-Type来用post方法提交。这种编码使用长边界字符串把请求主体分离成多个部分,对于文本数据,手动创建”multipart/form-data”请求主体是可能的,但很复杂。

XHR2定义了新的FormData api,容易实现多部分请求主体。首先,使用构造函数创建FormData对象,然后按需多次调用对象的append()方法把各部分添加到请求中,最后,把FormData对象传递给send()方法。
[b]3. 中止请求和超时abort[/b]
可以通过调用XMLHttpRequest对象的abort()方法来取消正在进行的http请求。Abort()方法在所有的XMLHttpRequest版本和XHR2中可用,调用方法时触发abort事件。


[b]4. 跨域http请求[/b]
作为同源策略的一部分,XMLHttpRequest对象通常仅可以发起和文档具有相同服务器的http请求。这个限制关闭了安全漏洞,但阻止了大量合适使用的跨域请求。可以在<form>和<iframe>中使用跨域url,而浏览器显示最终的跨域文档,但浏览器不允许原始脚本查找跨域文档的内容。使用XMLHttpRequest,文档内容都是通过responseText属性暴露,所以同源策略不允许XMLHttpRequest进行跨域请求。因此,<script>也取代了XMLHttpRequest成为主流Ajax传输协议。

[color=red][b]借助<script>发送http请求:JSONP[/b][/color]
只需设置<script>元素的src属性(加入它还没插入到document中,需要插入进去),然后浏览器会发送一个请求以下载src属性所指向的url。使用<script>元素进行Ajax传输的一个主要原因是,它不受同源策略的影响,因此可以使用它们从其他的服务器请求数据,第二个原因是包含JSON编码数据的响应体会自动解码(即执行)。

这种使用<script>元素作为Ajax传输的技术称为JSONP,若http请求所得到的响应数据时经过json编码的,则适合使用该技术。

当通过<script>元素调用数据时,响应内容必须用javascript函数名和[b]圆括号包裹起来[/b],而不是发送这样一段JSON数据:
[1, 2, {“buckle”:”my shoe”}]
应该发送这样一个包裹后的JSON响应:
handleResponse(
[1, 2, {“buckle”:”my shoe”}]
)

包裹后的响应会成为<script>元素的内容,它先判断JSON编码后的数据(毕竟是一个javascript表达式),然后把它传递给handleResponse()函数。

为了可行起见,我们必须通过某种方式告诉服务,它正在从一个<script>元素调用,必须返回一个JSONP响应,而不是普通的JSON响应。这个可以通过在URL中添加一个查询参数实现,例如追“?jsonp”(或“&jsonp”)。

在实践中,支持JSONP的服务不会强制指定客户端必须实现的回调函数名称,比如handleResponse。相反,他们使用查询参数的值,[b]允许客户端指定一个函数名[/b](如:?jsonp=callback)。
还可以参考:
[url]http://www.w3cmm.com/ajax/jsonp.html[/url]
[url]http://www.cnblogs.com/jkswjw/p/3173758.html[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值