天津做网站找津坤科技专业,c2c平台的产品类型,网站建设在360属于什么类目,建筑培训网首页安全员文章简介
本篇文章为【JavaScript 漫游】专栏的第 034 篇文章#xff0c;对浏览器模型的 XMLHttpRequest 对象#xff08;AJAX#xff09;的知识点进行了总结。
XMLHttpRequest 对象概述
浏览器与服务器之间#xff0c;采用 HTTP 协议通信。用户在浏览器地址栏键入一个网…
文章简介
本篇文章为【JavaScript 漫游】专栏的第 034 篇文章对浏览器模型的 XMLHttpRequest 对象AJAX的知识点进行了总结。
XMLHttpRequest 对象概述
浏览器与服务器之间采用 HTTP 协议通信。用户在浏览器地址栏键入一个网址或者通过网页表单向服务器提交内容这时浏览器就会向服务器发出 HTTP 请求。
1999年微软公司发布 IE 浏览器5.0版第一次引入新功能允许 JavaScript 脚本向服务器发起 HTTP 请求。这个功能当时并没有引起注意直到2004年 Gmail 发布和2005年 Google Map 发布才引起广泛重视。2005年2月AJAX 这个词第一次正式提出它是 Asynchronous JavaScript and XML 的缩写指的是通过 JavaScript 的异步通信从服务器获取 XML 文档从中提取数据再更新当前网页的对应部分而不用刷新整个网页。后来AJAX 这个词就成为 JavaScript 脚本发起 HTTP 通信的代名词也就是说只要用脚本发起通信就可以叫做 AJAX 通信。W3C 也在2006年发布了它的国际标准。
具体来说AJAX 包括以下几个步骤。
创建 XMLHttpRequest 实例发出 HTTP 请求接收服务器传回的数据更新网页数据
概括起来就是一句话AJAX 通过原生的 XMLHttpRequest 对象发出 HTTP 请求得到服务器返回的数据后再进行处理。现在服务器返回的都是 JSON 格式的数据XML 格式已经过时了但是 AJAX 这个名字已经成了一个通用名词字面含义已经消失了。
XMLHttpRequest 对象是 AJAX 的主要接口用于浏览器与服务器之间的通信。尽管名字里面有 XML 和 Http 它实际上可以使用多种协议比如 file 或 ftp发送任何格式的数据包括字符串和二进制。
XMLHttpRequest 本身是一个构造函数可以使用 new 命令生成实例。它没有任何参数。
var xhr new XMLHttpRequest();一旦新建实例就可以使用 open() 方法指定建立 HTTP 连接的一些细节。
xhr.open(GET, http://www.example.com/page.php, true);第一个参数指定方法类型第二个参数指定服务器网址第三个参数表示是否为异步。
然后指定回调函数监听通信状态readyState 属性的变化。
xhr.onreadystatechange handleStateChange;function handleStateChange() {// ...
}一旦 XMLHttpRequest 实例的状态发生变化就会调用监听函数 handleStateChange。
最后使用 send() 方法实际发出请求。
xhr.send(null);send() 的参数为 null表示发送请求的时候不带有数据体。如果发送的是 POST 请求这里就需要指定数据体。
一旦拿到服务器返回的数据AJAX 不会刷新整个网页而是只更新网页里面的相关部分从而不打断用户正在做的事情。
注意AJAX 只能向同源网址协议、域名、端口都相同发出 HTTP 请求如果发出跨域请求就会报错。
var xhr new XMLHttpRequest();xhr.onreadystatechange function() {// 通信成功时状态值为 4if (xhr.readyState 4) {if (xhr.status 200) {console.log(xhr.responseText);} else {console.log(xhr.statusText);}}
};xhr.onerror function (e) {console.log(xhr.statusText);
};xhr.open(GET, /endpoint, true);
xhr.send(null);XMLHttpRequest 的实例属性
readyState
返回一个整数表示实例对象的当前状态只读可能返回以下值。
0表示 XMLHttpRequest 实例已经生成但是实例的 opne() 还没有被调用1表示 open() 方法已经被调用但是实例的 sned() 还没有调用仍然可以使用实例的 setRequestHeader()设定 HTTP 请求的头信息2表示实例的 send() 方法已经调用并且服务器返回的头信息和状态码已经收到3表示正在接收服务器传来的数据体body 部分。这时如果实例的 responseType 属性等于 text 或者空字符串responseText 属性就会包含已经收到的部分信息4表示服务器返回的数据已经完全接收或者本次接收已经失败
通信过程中每当实例对象发生状态变化它的 readyState 属性的值就会改变。这个值每一次变化都会触发 readyStateChange 事件。
var xhr new XMLHttpRequest();if (xhr.readyState 4) {// 请求结束处理服务器返回的数据
} else {// 显示提示“加载中……”
}onreadystatechange
指向一个监听函数readystatechange 事件发生时实例的 readyState 属性变化就会执行这个属性。
另外如果使用实例的 abort()终止 XMLHttpRequest 请求也会造成 readyState 属性变化导致调用 XMLHttpRequest.onreadystatechange 属性。
var xhr new XMLHttpRequest();
xhr.open( GET, http://example.com , true );
xhr.onreadystatechange function () {if (xhr.readyState ! 4 || xhr.status ! 200) {return;}console.log(xhr.responseText);
};
xhr.send();response
服务器返回的数据体即 HTTP 响应的 body 部分。它可能是任何数据类型比如字符串、对象、二进制对象等等具体的类型由 XMLHttpRequest.responseType 属性决定。该属性只读。
如果本次请求没有成功或者数据不完整该属性等于 null。但是如果 responseType 属性等于 text 或空字符串在请求没有结束之前readyState 等于 3 的阶段response 属性包含服务器已经返回的部分数据。
var xhr new XMLHttpRequest();xhr.onreadystatechange function () {if (xhr.readyState 4) {handler(xhr.response);}
}responseType
服务器返回数据的类型。这个属性可写可以在调用 open() 之后、send() 之前设置这个属性的值告诉服务器返回指定类型的数据。如果 responseType 设为空字符串就等同于默认值 text。
XMLHttpRequest.responseType 属性可以等于以下值。
“”空字符串等同于 text表示服务器返回文本数据“arrarybuffer”ArrayBuffer 对象表示服务器返回二进制数组“blob”Blob 对象表示服务器返回二进制对象“document”Document 对象表示服务器返回一个文档对象“json”JSON 对象“text”字符串
上面几种类型之中text 类型适合大多数情况而且直接处理文本也比较方便。document 类型适合返回 HTML / XML 文档的情况这意味着对于那些打开 CORS 的网站可以直接用 Ajax 抓取网页然后不用解析 HTML 字符串直接对抓取回来的数据进行 DOM 操作。blob 类型适合读取二进制数据比如图片文件。
var xhr new XMLHttpRequest();
xhr.open(GET, /path/to/image.png, true);
xhr.responseType blob;xhr.onload function(e) {if (this.status 200) {var blob new Blob([xhr.response], {type: image/png});// 或者var blob xhr.response;}
};xhr.send();如果将这个属性设为 ArrayBuffer就可以按照数组的方式处理二进制数据。
var xhr new XMLHttpRequest();
xhr.open(GET, /path/to/image.png, true);
xhr.responseType arraybuffer;xhr.onload function(e) {var uInt8Array new Uint8Array(this.response);for (var i 0, len uInt8Array.length; i len; i) {// var byte uInt8Array[i];}
};xhr.send();如果将这个属性设为 json浏览器就会自动对返回数据调用 JSON.parse() 方法。也就是说从 xhr.response 属性注意不是 xhr.responseText 属性得到的不是文本而是一个 JSON 对象。
responseText
从服务器接收到的字符串该属性为只读只有 HTTP 请求完成接收以后该属性才会包含完整的数据。
var xhr new XMLHttpRequest();
xhr.open(GET, /server, true);xhr.responseType text;
xhr.onload function () {if (xhr.readyState 4 xhr.status 200) {console.log(xhr.responseText);}
};xhr.send(null);responseXML
返回从服务器接收到的 HTML 或 XML 文档对象只读。如果本次请求没有成功或者收到的数据不能被解析为 XML 或 HTML该属性等于 null。
该属性生效的前提是 HTTP 响应的 Content-Type 头信息等于 text/xml 或 application/xml。这要求在发送请求前XMLHttpRequest.responseType 属性要设为 document。如果 HTTP 响应的 Content-Type 头信息不等于 text/xml 和 application/xml但是从 responseXML 拿到数据即把数据按照 DOM 格式解析那么需要手动调用 XMLHttpRequest.overrideMimeType()强制进行 XML 解析。
该属性得到的数据是直接解析后的文档 DOM 树。
var xhr new XMLHttpRequest();
xhr.open(GET, /server, true);xhr.responseType document;
xhr.overrideMimeType(text/xml);xhr.onload function () {if (xhr.readyState 4 xhr.status 200) {console.log(xhr.responseXML);}
};xhr.send(null);responseURL
发送数据的服务器的网址。
var xhr new XMLHttpRequest();
xhr.open(GET, http://example.com/test, true);
xhr.onload function () {// 返回 http://example.com/testconsole.log(xhr.responseURL);
};
xhr.send(null);注意这个属性的值与 open() 指定的请求网址不一定相同。如果服务器端发生跳转这个属性返回最后实际返回数据的网址。另外如果原始 URL 包括锚点fragment该属性会把锚点剥离。
status 和 statusText
status 返回一个整数表示服务器回应的 HTTP 状态码。一般来说如果通信成功的话这个状态码是 200如果服务器没有返回状态码那么这个属性默认是 200。请求发出之前该属性为 0。该属性只读。
200OK访问正常301Moved Permanently永久移动302Moved temporarily暂时移动304Not Modified未修改307Temporary Redirect暂时重定向401Unauthorized未授权403Forbidden禁止访问404Not Found未发现指定网址500Internet Server Error服务器发生错误
基本上只有 2xx 和 304 的状态码表示服务器返回是正常状态。
if (xhr.readyState 4) {if ( (xhr.status 200 xhr.status 300)|| (xhr.status 304) ) {// 处理服务器的返回数据} else {// 出错}
}statusText 属性返回一个字符串表示服务器发送的状态提示。不同于 status 属性该属性包含整个状态信息比如 “OK” 和 “Not Found”。在请求发送之前即调用 open() 之前该属性的值是空字符串如果服务器没有返回状态提示该属性的值默认为“OK”。该属性为只读属性。
timeout 和 ontimeout
timeout 返回一个整数表示多少毫秒后如果请求仍然没有得到结果就会自动终止。如果该属性等于 0就表示没有时间限制。
ontimeout 属性用于设置一个监听函数如果发生 timeout 事件就会执行这个监听函数。
var xhr new XMLHttpRequest();
var url /server;xhr.ontimeout function () {console.error(The request for url timed out.);
};xhr.onload function() {if (xhr.readyState 4) {if (xhr.status 200) {// 处理服务器返回的数据} else {console.error(xhr.statusText);}}
};xhr.open(GET, url, true);
// 指定 10 秒钟超时
xhr.timeout 10 * 1000;
xhr.send(null);事件监听属性
XMLHttpRequest 对象可以对以下事件指定监听函数。
XMLHttpRequest.onloadstartloadstart 事件HTTP 请求发出的监听函数XMLHttpRequest.onprogressprogress事件正在发送和加载数据的监听函数XMLHttpRequest.onabortabort 事件请求中止比如用户调用了abort()方法的监听函数XMLHttpRequest.onerrorerror 事件请求失败的监听函数XMLHttpRequest.onloadload 事件请求成功完成的监听函数XMLHttpRequest.ontimeouttimeout 事件用户指定的时限超过了请求还未完成的监听函数XMLHttpRequest.onloadendloadend 事件请求完成不管成功或失败的监听函数
xhr.onload function() {var responseText xhr.responseText;console.log(responseText);// process the response.
};xhr.onabort function () {console.log(The request was aborted);
};xhr.onprogress function (event) {console.log(event.loaded);console.log(event.total);
};xhr.onerror function() {console.log(There was an error!);
};progress 事件的监听函数有一个事件对象参数该对象有三个属性loaded 属性返回已经传输的数据量total 属性返回总的数据量lengthComputable 属性返回一个布尔值表示加载的进度是否可以计算。所有这些监听函数里面只有 progress 事件的监听函数有参数其他函数都没有参数。
注意如果发生网络错误比如服务器无法连通onerror 事件无法获取报错信息。也就是说可能没有错误对象所以这样只能显示报错的提示。
withCredentials
表示跨域请求时用户信息比如 Cookie 和认证的 HTTP 头信息是否会包含在请求之中默认为false即向 example.com 发出跨域请求时不会发送 example.com 设置在本机上的 Cookie如果有的话。
如果需要跨域 AJAX 请求发送 Cookie需要 withCredentials 属性设为 true。注意同源的请求不需要设置这个属性。
var xhr new XMLHttpRequest();
xhr.open(GET, http://example.com/, true);
xhr.withCredentials true;
xhr.send(null);为了让这个属性生效服务器必须显式返回 Access-Control-Allow-Credentials 这个头信息。
Access-Control-Allow-Credentials: truewithCredentials 属性打开的话跨域请求不仅会发送 Cookie还会设置远程主机指定的 Cookie。反之也成立如果 withCredentials 属性没有打开那么跨域的 AJAX 请求即使明确要求浏览器设置 Cookie浏览器也会忽略。
注意脚本总是遵守同源政策无法从 document.cookie 或者 HTTP 回应的头信息之中读取跨域的 CookiewithCredentials 属性不影响这一点。
upload
XMLHttpRequest 不仅可以发送请求还可以发送文件这就是 AJAX 文件上传。发送文件以后通过 XMLHttpRequest.upload 属性可以得到一个对象通过观察这个对象可以得知上传。主要方法就是监听这个对象的各种事件loadstart、loadend、load、abort、error、progress、timeout。
假定网页上有一个 progress 元素。
progress min0 max100 value00% complete/progress文件上传时对 upload 属性指定 progress 事件的监听函数即可获得上传的进度。
function upload(blobOrFile) {var xhr new XMLHttpRequest();xhr.open(POST, /server, true);xhr.onload function (e) {};var progressBar document.querySelector(progress);xhr.upload.onprogress function (e) {if (e.lengthComputable) {progressBar.value (e.loaded / e.total) * 100;// 兼容不支持 progress 元素的老式浏览器progressBar.textContent progressBar.value;}};xhr.send(blobOrFile);
}upload(new Blob([hello world], {type: text/plain}));XMLHttpRequest 的实例方法
open()
用于指定 HTTP 请求的参数或者说初始化 XMLHttpRequest 实例对象。它一共可以接受五个参数。
void open(string method,string url,optional boolean async,optional string user,optional string password
);method表示 HTTP 动词方法比如 GET、POST、PUT、DELETE、HEAD 等url表示请求发送目标 URLasync表示请求是否为异步默认为 true。如果设为 false则 send() 方法只有等到收到服务器返回了结果才会进行了下一步操作。该参数可选。由于同步 AJAX 请求会造成浏览器失去响应许多浏览器已经在主线程使用只允许 Worker 里面使用。所以这个参数轻易不应该设为 falseuser用户名默认为空字符串可选password密码默认为空字符串可选
注意如果对使用过 open() 方法的 AJAX 请求再次使用这个方法等同于调用 abort() 即终止请求。
send()
用于实际发出 HTTP 请求。它的参数是可选的如果不带参数就表示 HTTP 请求只有一个 URL没有数据体典型例子就是 GET 请求如果带有参数就表示除了头信息还带有包含具体数据的信息体典型例子就是 POST 请求。
var xhr new XMLHttpRequest();
xhr.open(GET,http://www.example.com/?id encodeURIComponent(id),true
);
xhr.send(null);GET 请求的参数作为查询字符串附加在 URL 后面。
var xhr new XMLHttpRequest();
var data email encodeURIComponent(email) password encodeURIComponent(password);xhr.open(POST, http://www.example.com, true);
xhr.setRequestHeader(Content-Type, application/x-www-form-urlencoded);
xhr.send(data);注意所有 XMLHttpRequest 的监听事件都必须在 send() 方法调用之前设定。
send 方法的参数就是发送的数据。多种格式的数据都可以作为它的参数。
void send();
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(String data);
void send(FormData data);如果 send() 发送 DOM 对象在发送之前数据会先被串行化。如果发送二进制数据最好是发送 ArrayBufferView 或 Blob对象这使得通过 Ajax 上传文件成为可能。
下面是发送表单数据的例子。FormData对象可以用于构造表单数据。
var formData new FormData();formData.append(username, 张三);
formData.append(email, zhangsanexample.com);
formData.append(birthDate, 1940);var xhr new XMLHttpRequest();
xhr.open(POST, /register);
xhr.send(formData);它的效果与发送下面的表单数据是一样的。
form idregistration nameregistration action/registerinput typetext nameusername value张三input typeemail nameemail valuezhangsanexample.cominput typenumber namebirthDate value1940input typesubmit onclickreturn sendForm(this.form);
/form下面的例子是使用 FormData 对象加工表单数据然后再发送。
function sendForm(form) {var formData new FormData(form);formData.append(csrf, e69a18d7db1286040586e6da1950128c);var xhr new XMLHttpRequest();xhr.open(POST, form.action, true);xhr.onload function() {// ...};xhr.send(formData);return false;
}var form document.querySelector(#registration);
sendForm(form);setRequestHeader()
用于设置浏览器发送的 HTTP 请求的头信息。该方法必须在open() 之后、send() 之前调用。如果该方法多次调用设定同一个字段则每一次调用的值会被合并成一个单一的值发送。
该方法接受两个参数。第一个参数是字符串表示头信息的字段名第二个参数是字段值。
xhr.setRequestHeader(Content-Type, application/json);
xhr.setRequestHeader(Content-Length, JSON.stringify(data).length);
xhr.send(JSON.stringify(data));overrideMimeType()
用来指定 MIME 类型覆盖服务器返回的真正的 MIME 类型从而让浏览器进行不一样的处理。举例来说服务器返回的数据类型是 text/xml由于种种原因浏览器解析不成功报错这时就拿不到数据了。为了拿到原始数据我们可以把 MIME 类型改成text/plain这样浏览器就不会去自动解析从而我们就可以拿到原始文本了。
xhr.overrideMimeType(text/plain)注意该方法必须在 send() 方法之前调用。
修改服务器返回的数据类型不是正常情况下应该采取的方法。如果希望服务器返回指定的数据类型可以用 responseType 属性告诉服务器就像下面的例子。只有在服务器无法返回某种数据类型时才使用 overrideMimeType() 方法。
var xhr new XMLHttpRequest();
xhr.onload function(e) {var arraybuffer xhr.response;// ...
}
xhr.open(GET, url);
xhr.responseType arraybuffer;
xhr.send();getResponseHeader()
返回 HTTP 头信息指定字段的值如果还没有收到服务器回应或者指定字段不存在返回 null。该方法的参数不区分大小写。
function getHeaderTime() {console.log(this.getResponseHeader(Last-Modified));
}
var xhr new XMLHttpRequest();
xhr.open(HEAD, yourpage.html);
xhr.onload getHeaderTime;
xhr.send();getAllResponseHeaders()
返回一个字符串表示服务器发来的所有 HTTP 头信息。格式为字符串每个头信息之间使用 CRLF 分隔回车换行如果没有收到服务器回应该属性为null。如果发生网络错误该属性为空字符串。
var xhr new XMLHttpRequest();
xhr.open(GET, foo.txt, true);
xhr.send();xhr.onreadystatechange function () {if (this.readyState 4) {var headers xhr.getAllResponseHeaders();}
}上面代码用于获取服务器返回的所有头信息。它可能是下面这样的字符串。
date: Fri, 08 Dec 2017 21:04:30 GMT\r\n
content-encoding: gzip\r\n
x-content-type-options: nosniff\r\n
server: meinheld/0.6.1\r\n
x-frame-options: DENY\r\n
content-type: text/html; charsetutf-8\r\n
connection: keep-alive\r\n
strict-transport-security: max-age63072000\r\n
vary: Cookie, Accept-Encoding\r\n
content-length: 6502\r\n
x-xss-protection: 1; modeblock\r\n然后对这个字符串进行处理。
var arr headers.trim().split(/[\r\n]/);
var headerMap {};arr.forEach(function (line) {var parts line.split(: );var header parts.shift();var value parts.join(: );headerMap[header] value;
});headerMap[content-length] // 6502abort()
用来终止已经发出的 HTTP 请求。调用这个方法以后readyState 属性变为4status 属性变为0。
var xhr new XMLHttpRequest();
xhr.open(GET, http://www.example.com/page.php, true);
setTimeout(function () {if (xhr) {xhr.abort();xhr null;}
}, 5000);XMLHttpRequest 实例的事件
readyStateChange 事件
readyState 属性的值发生改变就会触发 readyStateChange 事件。
progress 事件
上传文件时XMLHttpRequest 实例对象本身和实例的 upload 属性都有一个progress 事件会不断返回上传的进度。
var xhr new XMLHttpRequest();function updateProgress (oEvent) {if (oEvent.lengthComputable) {var percentComplete oEvent.loaded / oEvent.total;} else {console.log(无法计算进展);}
}xhr.addEventListener(progress, updateProgress);xhr.open();load 事件、error 事件、abort 事件
load 事件表示服务器传来的数据接收完毕error 事件表示请求出错abort 事件表示请求被中断比如用户取消请求。
var xhr new XMLHttpRequest();xhr.addEventListener(load, transferComplete);
xhr.addEventListener(error, transferFailed);
xhr.addEventListener(abort, transferCanceled);xhr.open();function transferComplete() {console.log(数据接收完毕);
}function transferFailed() {console.log(数据接收出错);
}function transferCanceled() {console.log(用户取消接收);
}loadend 事件
abort、load 和 error 这三个事件会伴随一个 loadend 事件表示请求结束但不知道其是否成功。
xhr.addEventListener(loadend, loadEnd);function loadEnd(e) {console.log(请求结束状态未知);
}timeout 事件
服务器超过指定时间还没有返回结果就会触发 timeout 事件。