XMLHttpRequest 等级 2 介绍
2013年06月21日 10:59:27 苍月代表我 阅读数 718

介绍
XMLHttpRequest 可以让开发者发送 HTTP 与 HTTPS 请求并在不重載当前页面的情况下更动页面。一般常用的两个使用情景是:提交表单与取得更多内容。
在之前的 XMLHttpRequest 中,请求的内容只能是文本、HTML 或 XML。要发送索引键值配对需要使用读取与写入皆不干净的语法 − URL 编码字符串。
之前的 XHR 必须遵守让跨域请求相当困难的相同来源政策。举例来说,要是没有像是 Flash 补助 XHR 或是代理服务器之类的中介,开发者不能在 http://foo.example/ 与 http://bar.example/ 之间分享数据。要在子域间(例如 http://foo.example 与 http://www.foo.example)分享数据,开发者必须在两个来源的脚本中设置 document.domain,但是这样做又会有安全风险。
以前的 XHR 可以上传档案吗?不行。开发者必须使用依赖插件的 SWFUpload,不然就是需要一个隐藏 iframe,但是后者又欠缺用户端的进展事件。
本文将会踏入 XMLHttpRequest 的一些最新进展并详述 Opera 12 的支持情形。
XMLHttpRequest 有什么新东西
在 XMLHttpRequest 规范与浏览器支持有所进步的现在,开发者可以:
设置请求超时
透过 FormData 对象管理数据
传输二位元数据
监听数据传输的进展
进行更安全的跨域请求
覆盖媒体类型与响应的媒体形态
设置并处理超时
有时候有可能是因为网路频宽不够或是服务器响应时间太长导致请求的完成速度很慢,这会造成应用反应迟钝,对用户体验有不良的影响。
XHR 现在已经有处理这个问题的方法了:请求超时。开发者可以用 timeout 属性指定应用的等待时间,如果超过了这个时间,开发者可以让应用进行别的工作。下面的例子设置了三秒(3000 微秒)的超时:

function makeRequest() {

var url = ‘data.json’;

var onLoadHandler = function(event){

 // 解析 JSON 并建一个数组。

}

var onTimeOutHandler = function(event){

var content = document.getElementById('content'),p = document.createElement('p'),msg = document.createTextNode('再等一下!');p.appendChild(msg);content.appendChild(p);// 重新启动请求。event.target.open('GET', url);// 也可以用一个更长的超时,盖掉原来的。event.target.timeout = 6000;event.target.send();

}

var xhr = new XMLHttpRequest();

xhr.open(‘GET’, url);

xhr.timeout = 3000;

xhr.onload = onLoadHandler;

xhr.ontimeout = onTimeOutHandler;

xhr.send();

}

window.addEventListener(‘DOMContentLoaded’, makeRequest, false);
当经过了三秒但是响应数据还没到达时,上面例子会告知用户请求要花多一点时间,并启动一个设有更长超时时间的请求(观看 XHR 超时演示)。在 timeout 事件监听中重设超时时间不是必要的,但是在这个例子中,由于新的 URL 的响应总是会超过原来的超时时间,这里才为了避免循环重设超时时间。
到目前为止,Chrome 与 Safari 不支持 XHR 超时。Opera、Firefox 与 IE 10 则支持。IE 8 与 9 也支持 XDomainRequest 对象上的超时。
从别的网域请求数据
之前 XHR 的一个限制是相同来源政策:发出请求的文档和被请求的文档必须有相同的协议、域名、端口。一个从 http://www.foo.example 至 http://www.foo.example:5050 的跨端口请求会导致浏览器抛出安全例外(除了允许跨端口请求的旧版本 IE 以外)。
而现在 XMLHttpRequest 已经在跨来源资源共享(CORS)启动的时候支持跨来源请求了。
尽管 IE10 支持跨域 XMLHttpRequest,但是 IE 8 与 9 不支持。然而,在 IE 8 与 9 下可以用作用差不多的 XDomainRequest 对象。
除了使用绝对 URL 而不是相对 URL 以外,跨来源请求长得跟相同来源请求差不多:

var xhr = new XMLHttpRequest();

var onLoadHandler = function(event) {

/* 用响应作点事 */

}

xhr.open(‘GET’,‘http://other.server/and/path/to/script’);

xhr.onload = onLoadHandler;

xhr.send();
重要的不同点在于目标 URL 必须透过发送 Access-Control-Allow-Origin 响应标头来表示允许存取。
跨来源资源共享概论
请参阅《DOM access control using cross-origin resource sharing》以更深入了解 CORS,这里仅介绍两个标头:Origin 请求标头,与 Access-Control-Allow-Origin 响应标头。
Origin 请求标头
Opera 与其他浏览器会在进行跨来源 XHR 请求的时候自动加入 Origin 标头,如同下面的例子:
GET /data.xml HTTP/1.1
User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.10.289 Version/12.00
Host: datahost.example
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, /;q=0.1
Accept-Language: en,en-US
Accept-Encoding: gzip, deflate
Referer: http://requestingserver.example/path/to/askingdocument.html
Connection: Keep-Alive
Origin: http://requestingserver.example
Origin 一般包含请求文档的协议、域名、端口。Origin 不是一个“网页作者请求标头”,也就是说 Origin 不能用 setRequestHeader() 方法设置或更改 ― 用户代理会忽略这种设置。Origin 标头唯一的目的就是告知目标服务器该请求的来源。请注意 Origin 标头的结尾没有斜线。
Access-Control-Allow-Origin 响应标头
Access-Control-Allow-Origin 标头是在目标服务器收到跨来源请求时回应的标头。Access-Control-Allow-Origin 告诉用户代理是否应给予发出请求的来源存取
权限。 除非被请求的 URL 允许跨域存取,否则与跨来源 XHR 请求相关的 DOM 操作皆不会完成。以下是例子:
HTTP/1.1 200 OK
Date: Fri, 27 May 2011 21:27:14 GMT
Server: Apache/2
Last-Modified: Fri, 27 May 2011 19:29:00 GMT
Accept-Ranges: bytes
Content-Length: 1830
Keep-Alive: timeout=15, max=97
Connection: Keep-Alive
Content-Type: application/xml; charset=UTF-8
Access-Control-Allow-Origin: *
这个例子用通配符(*)让任何来源的文档都可以存取此 URL,这在开发者要提供一个公用的 API 的时候是无所谓,但是在其他的使用情景里,开发者应该设置比较具体的值。
在跨域请求中发送认证讯息
开发者可能会有要在跨域请求中发送 Cookie 数据的状况,这时候 withCredentials 属性就登场了。withCredentials 属性是一个布尔属性,用来告知浏览器是否应该随同请求发送用户认证讯息。默认情况下,认证讯息旗帜为 false。在下面的代码中,我们假设请求是一个从 http://foo.example 送到 http://other.server 的请求:

var xhr = new XMLHttpRequest();

var onLoadHandler = function(event) {

doSomething(event.target.responseText);

}

xhr.open(‘GET’, ‘http://other.server/and/path/to/script’);

xhr.withCredentials = true;

xhr.onload = onLoadHandler;

xhr.send();
XHR 认证讯息演示使用 Cookie 作为计数器来追踪访问量。去检视请求与响应的数据(可以用 Dragonfly 的网路面板)就会看到浏览器的确在发送请求 Cookie 并收到响应 Cookie。服务器端脚本会回传包含新的访问计数的文本,并更新 Cookie 的值。
请记得在使用代有认证讯息的请求的时候:
仅在跨来源请求的时候需要设置 withCredentials。
请求 URI 的 Access-Control-Allow-Origin 标头不能包含通配符(*)。
请求 URI 的 Access-Control-Allow-Credentials 标头必须设为 true。
除非设有 Access-Control-Expose-Headers 标头,getAllRequestHeaders() 仅可以取得一部分的响应标头。
在相同来源的情况下,浏览器求会忽略认证讯息旗帜。代有通配符的 Access-Control-Allow-Origin 标头会让浏览器抛出异常。若 Access-Control-Allow-Credentials 是 false,浏览器会发送并接受 Cookie,但是不能从 DOM 中取得。
透过 FromData 对象发送索引键值配对
在之前的版本中,透过 XHR 发送的数据必须是一个 URL 编码或是(利用 JSON.strigify() 得到的)JSON 字符串。下面的例子使用 URL 编码:

var msg = ‘field1=foo&field2=bar’;

var xhr = new XMLHttpRequest();

xhr.open(‘POST’,’/processing_script’);

xhr.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);

xhr.send(msg);
但是现在开发者可以使用 FormData 对象跟它提供的索引键值配对语法。这个语法有三种个特点:
让脚本更容易读。
跟一般的 HTML 表单一样,数据以索引键值配对发送。
FormData 对象会使数据以 multipart/form-data 编码发送,让 XHR 可以发送二进制的数据。
FormData 跟 ActionScript 3.0 的 URLVariables 使用起来的感觉很像:先创建一个 FormData 对象,再使用 append() 方法添加数据。append() 方法使用两个参数:键与值。FormData 的每一个键会变成服务器端脚本可以使用的一个变量名。以下是个例子:

var xhr = new XMLHttpRequest();

var dataToSend = new FormData(); // 创建一个 FormData 对象

xhr.open(‘POST’,’/processing_script’);

dataToSend.append(‘name’, ‘哆啦A梦’); // 在对象上添加数据

dataToSend.append(‘age’, ‘11’);

dataToSend.append(‘hobby’, ‘吃铜锣烧’);

xhr.send(dataToSend); // 发送对象
在最后面的地方 FormData 对象被当成 send() 方法的参数:xhr.send(dataToSend)。上面的例子并没有在 XMLHttpRequest 对象上设置 Content-Type 标头。来看看 Opera 传了什么请求标头:
POST /processing_script HTTP/1.1
User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8) Presto/2.10.289 Version/12.00
Host: datahost.example
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, /;q=0.1
Accept-Language: en,en-US
Accept-Encoding: gzip, deflate
Expect: 100-continue
Referer: http://datahost.example/upload/
Connection: Keep-Alive
Content-Length: 4281507
Content-Type: multipart/form-data; boundary=----------J2GMKTyAkjRjNgFzKv3VBJ
由于例子里用了 FormData 对象,Opera 帮忙添加了 Content-Type 标头。其他浏览器也是这样的情形。
由 HTML 表单创建 FormData
开发也可以使用 FormData 发送表单的值,只要将表单传给 FormData 对象就可以了(XHR FormData 演示),如下:

var submitHandler = function(event) {

var dataToSend = new FormData(event.target), xhr = new XMLHttpRequest();

xhr.open(‘POST’, ‘/processing_script’);

xhr.send(dataToSend);

}

var form = document.getElementById(‘myform’);

form.addEventListener(‘submit’, submitHandler, false);
FormData 仍是不受信任的数据。请将由 FromData 对象来的数据当成与一般的表单提交得到的数据无异。
使用进度事件监测数据传输
现在的 XMLHttpRequest 已经提供了让开发者监测数据传输的进度事件属性。在之前的时候,开发者需要监听 readystatechange 事件,如下面的例子:

var xhr = new XMLHttpRequest();

var onReadyStateHandler = function(event) {

if( event.target.readyState == 4 && event.target.status == 200){

/* 处理响应 */

}

}

xhr.open(‘GET’,’/path_to_data’);

xhr.onreadystatechange = onReadyStateHandler;

xhr.send();
虽然 readystatechange 在开发者仅注意所有数据的下载完全时间的情形下足够用了,但是 readystatechange 并不能提供到底已经接收了多少数据的即时信息。为了向后兼容,readystatechange 仍是规范的一部分,但是新的 ProgressEvent 接口可靠多了。新的规范为 XMLHttpRequest 与 XMLHttpRequestUpload 对象加上了七个事件。
以下是 XMLHttpRequest 的 ProgressEvent 列表:
属性
形态
解释
onloadstart
loadstart
请求开始的时候。
onprogress
progress
读取与发送数据的时候会不断触发本事件。
onabort
abort
经由调用 abort() 方法或浏览到别的页面使得请求退出的时候。
onerror
error
请求发生错误的时候。
onload
load
请求成功完成的时候。
ontimeout
timeout
开发者指定的超时时间已经超过了但是请求仍未能完成的时候。
onloadend
loadend
不管请求成功与否,请求已经完成的时候。
由于 XMLHttpRequest 与 XMLHttpRequestUpload 继承 EventTarget 接口,开发者者可以在代码中使用事件属性(如 onload)或是 addEventListener 方法。下面的范例使用 addEventListener。
监测上传的进度
所有基于 XMLHttpRequest 的档案上传都会产生一个 XMLHttpRequestUpload 对象,开发者可以通过 XMLHttpRequest 的 upload 属性取得该对象。要监测上传进度,开发者需要监听 XMLHttpRequestUpload 对象上的事件。
下面的代码监听了 progress、load 与 error 事件:

var onProgressHandler = function(event) {

if(event.lengthComputable) {

var howmuch = (event.loaded / event.total) * 100;document.querySelector('progress').value = Math.ceil(howmuch);

} else {

console.log("无法取得档案的大小。");

}

}

var onLoadHandler = function() {

displayLoadedMessage();

}

var onErrorHandler = function() {

displayErrorMesssage();

}

xhr.upload.addEventListener(‘progress’, onProgressHandler, false);

xhr.upload.addEventListener(‘load’, onLoadHandler, false);

xhr.upload.addEventListener(‘error’, onErrorHandler, false);
情特别注意 onProgressHandler 函式里用的 lengthComputable、loaded 与 total,这些都是进度事件对象上的属性。lengthComputable 属性告诉开发者浏览器可否侦测上传档案的大小,而 loaded 与 total 告诉开发者已上传了多少个字节与档案的总大小。请看 XHR 进度事件的演示。
这些事件监测了浏览器传输数据到服务器或服务器接收数据的进度。在上传的情况下,有可能在触发 load 事件与服务器回传响应之间有一个时间差。这个时间差的长度取决于档案的大小、服务器的资源与网路的速度。
上面的例子为 XMLHttpRequestUpload 设置了事件监听,要监档案下载要在 XMLHttpRequest 对象上添加事件监听。
强制变更响应的 MIME 形态
MIME 不正确的情况在万维网上十分常见。有时候 XML 数据的响应标头有 Content-type: text/html,使得 xhr.responseXML 变成 null。
为了确保浏览器依照开发者的意思处理这样的响应,开发者可以使用 overrideMimeType() 方法。在下面的例子里,data.xml 会回传下列的响应标头:
Date: Sat, 04 Jun 2011 03:11:31 GMT
Server: Apache/2.2.17
Access-Control-Allow-Origin: *
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
也就是 XML 文档的内容形态是错误的。下面代码确保浏览器将 data.xml 视为 XML并设置 responseXML 属性:

var xhr = new XMLHttpRequest();

xhr.open(‘GET’, ‘data.xml’);

xhr.overrideMimeType(‘application/xml’);

xhr.send();

xhr.addEventListener(‘load’, function(event) {

console.log(event.target.responseXML);

}, false);
现在 xhr.responseXML 的之已经是一个 Document 对象了,也就是开发者可以像碰到正常的 XML 文档一样解析数据了。观看覆盖 XHR 的 MIME 形态的演示。
强制使用某种数据形态
开发者也可以使用 responseType 属性让浏览器将响应当成 text、json、arraybuffer、blob 或 document。
开发者必须在送出请求前设置 responseType 属性,就像 overrideMimeType 一样。下面的例子让 Opera 把响应当作是 document,并将 firstChild 写到控制台里(观看强制使用某种数据形态的演示):

var xhr = new XMLHttpRequest();

xhr.open(‘GET’,‘data.xml’);

xhr.responseType = ‘document’;

xhr.send();

xhr.addEventListener(‘load’, function(e) {

console.log(event.target.response.firstChild);

} false);
虽然 responseType 可以让开发者将图像数据当作一个字节数组而不是二位元字符串,但是它不会创造奇迹:在上面的例子中将 document 改成 json 会让 response 属性变成 null,因为 XML 不是 JSON。同样的,不合法的 JSON 数据也会让 response 变成 null。开发者需要在设置 responseType 的时候确保数据符合指定的形态而且合法。
注:在文章发布的这个时间点,Opera 尚未支持 blob 值,在 document 形态下也只之持 XML 而不支持 HTML。Chrome 与 Safari 不支持 json 值。
学习更多
这些 XMLHttpRequest 的进步对于用户端的交互性能是一种跃升。请阅读以下资源以获取更多关于 XMLHttpRequest、CORS 与相关 API 的讯息:
XMLHttpRequest specification
DOM access control using cross-origin resource sharing
Bruce Lawson 写的 The W3C file API
XDomainRequest Object (Internet Explorer 8 & 9)

<!--url字符串编码-->
<script>var submitHandler  =function (event) {var newVar = new formData(event.target);var xhr = new XMLHttpRequest();xhr.open("POST","/login");xhr.send(newVar);}var form = document.getElementById("myForm");//给form添加一个监听事件form.addEventListener('sumbit',submitHandler,false);</script>

XMLHttpRequest的请求方法相关推荐

  1. Ajax→异步的JavaScript和XML、HTTP请求响应、Ajax简介同步异步、XMLHttpRequest类的方法及属性、原生Ajax、Koa实现Ajax、接口文档、浏览器同源策略、反向代理

    浏览器服务器 HTTP请求响应 数据库后端语言 Ajax简介同步异步 Koa前端框架 XMLHttpRequest类的方法及属性 原生Ajax Koa实现Ajax JSON DOM 接口文档 浏览器同 ...

  2. javascript对XMLHttpRequest异步请求的面向对象封装

    对XMLHttpRequest异步请求的面向对象封装,需要的朋友可以参考下 function CallBackObject() { this.XmlHttp = this.GetHttpObject( ...

  3. HTTP协议的六种请求方法

    抛砖引玉,聊下概念性的东西先: HTTP协议 (Hyper Text Transfer Protocol) HTTP是一个基于TCP/IP通信协议来传递数据,包括html文件.图像.结果等,即是一个客 ...

  4. python中的请求方法_http协议的9种请求方法

    http协议的9种请求方法 在http/1.1协议中,定义了8种访问指定资源的方法,他们分别为 OPTIONS GET HEAD POST PUT PATCH DELETE TRACE CONNECT ...

  5. http的请求方法 GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE 说明

    2019独角兽企业重金招聘Python工程师标准>>> 超文本传输协议(HTTP, HyperText Transfer Protocol)是一种无状态的协议,它位于OSI七层模型的 ...

  6. 放在请求头目的_浅谈http的几种请求方法

    脑图 目前主流使用的 HTTP 协议的请求方法是比较固定的,并没有随着大版本的提升有过多改变. 按照 常用.非常用以及扩展可以分成上图中的 3 类.要彻底掌握这些 request methods,我们 ...

  7. Ajax异步请求方法(详细)

    使用ajax发送异步请求 原生js实现以及jquery ajax实现发送请求 文章目录 使用ajax发送异步请求 简介 实现方式 1.原生js实现 1.get请求 2.post请求 2.jquery ...

  8. 常用的HTTP请求方法

    前端日常发送HTTP请求最长用到GET, POST两种方法,如果是在一个符合RESTful设计规范的应用中, 常用到5个方法:GET.POST.PUT.PATCH.DELETE. PS: RESTfu ...

  9. HTTP请求方法之options请求

    HTTP请求方法之options请求 HTTP请求 最近在做unaipp H5网页端微信公众号登录授权时由于options请求导致code值失效问题.因此要避免服务器向后端发送options请求使用c ...

最新文章

  1. 戴尔sc系列存储阵列柜服务器,国产化的戴尔存储 到底都长什么样?
  2. Webx示例-PetStore分析1
  3. AnyChat Server SDK与SDK Filter Plus有何差异?
  4. 使用numpy生成one_hot
  5. 如何成为android开发工程师,android开发工程师薪资 如何成为一名合格的android开发工程师?...
  6. GitPages个人域名博客
  7. Codeforces 999F Cards and Joy 【dp】【性质】
  8. [Swift]loadNibNamed方法
  9. LeetCode 557. Reverse Words in a String III
  10. extjs设计器破解程序及开发调试工具
  11. python-gui-pyqt5的使用方法-8--实际案例可参考使用
  12. 渗透测试全套教程(从原理到实战)
  13. 高分辨率:遥感卫星影像
  14. 小样本条件下工业无损检测X光图像
  15. 怎么把word目录里面的“目录”两个字去掉
  16. python中ascii函数_ascii函数
  17. 用一个创业故事串起操作系统原理(五)
  18. 浅谈,如何获取MTK CPU信息 请看我是如何做的。一步步来吧
  19. win10系统服务器的ip地址,win10系统查看电脑IP地址和默认网关的操作方法
  20. FX5u控制4个伺服,一个完整的项目 程序用 标签分层,说明了定位控制中的公共参数设定、回原点、

热门文章

  1. java实现ecc加密:通过AES生成公钥加密数据,ECC加密公钥
  2. 《演讲之禅》读书笔记
  3. 说透缓存一致性与内存屏障
  4. 虚拟来电 - 伪装来电工具
  5. 实测:合宙ESP32C3开发板可以直接用Arduino开发
  6. 2017年5月许小年最新演讲:深圳人没房的,还是咬咬牙就买吧!
  7. 联通linux用户名是什么意思,揭秘 linux 通过新联通宽带拨号上网不成功原因及解决办法!...
  8. 房卡棋牌分析系列之微信登录
  9. c 程序设计语言 好难,C程序设计语言难点及分析
  10. WGS84以及各种坐标系