[TOC] ## 简单例子 ``` var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ // 通信成功时,状态值为4 if (xhr.readyState === 4){ if (xhr.status === 200){ console.log(xhr.responseText); } else { console.error(xhr.statusText); } } }; xhr.onerror = function (e) { console.error(xhr.statusText); }; xhr.open('GET', '/endpoint', true); xhr.send(null); ``` ## 属性 ### readyState * 0,实例已经生成,`open()`方法没被调用 * 1,`open()`方法已经调用,`send()`方法没有调用,仍可使用实例的`setRequestHeader()`方法,设定 HTTP 请求的头信息。 * 2,`send()`方法已经调用,并且服务器返回的头信息和状态码已经收到。 * 3,接收服务器的数据体(body)。这时,如果实例的`responseType`属性等于`text`或者空字符串,`responseText`属性就会包含已经收到的部分信息。 * 4,表示服务器返回的数据已经完全接收,或者本次接收已经失败。 ### onreadystatechange 添加 `readyState` 的变化 ### response 服务器返回的数据体 可以是任何数据类型,字符串、对象、二进制对象 ### responseType 返回的数据类型 * ""(空字符串):等同于`text`,表示服务器返回文本数据。 * "arraybuffer":ArrayBuffer 对象,表示服务器返回二进制数组。 * "blob":Blob 对象,表示服务器返回二进制对象。 * "document":Document 对象,表示服务器返回一个文档对象。 * "json":JSON 对象。 * "text":字符串。 如果设置返回值为 `json` 则`xhr.response` 返回json对象 不能通过 `responseText` 取得对象 ``` var xhr = new XMLHttpRequest(); xhr.open('get', 'test.php', true); xhr.responseType='json'; //设置发回值类型 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log(xhr.response.name); } else { console.error(xhr.status); } } } xhr.onerror = function () { console.log(xhr.statusText); } xhr.send(null) ``` ### responseText 从服务器接收到的字符串 如果没有指定返回类型,默认使用此方法 ### responseXML 返回执行后的DOM 文件 1. `Content-Type`是`text/html`和`application/xml`,只需设置 `responseType`属性为`document` 2. 如果 HTTP 回应的`Content-Type`头信息不等于`text/xml`和`application/xml`,还需设置`overrideMimeType('xml')` ``` xhr.responseType = 'document'; //若Content-type 不是 text/xml 或者 application/xml xhr.overrideMimeType('text/xml'); ``` ### responseURL 请求的地址 ### status / statusText 返回状态吗和描述 ### timeout / ontimeout 是指超时时间 超时触发的函数 ``` var xhr = new XMLHttpRequest(); xhr.open('GET', '/server); xhr.ontimeout = function () { console.error('The request for ' + url + ' timed out.'); }; xhr.timeout = 10 * 1000; // 指定 10 秒钟超时 xhr.send(null); ``` ### withCredentials 跨域请求时,是否包含用户信息(如Cookie 和认证的 HTTP 头信息) 默认为`false` ``` var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://example.com/', true); xhr.withCredentials = true; xhr.send(null); ``` ### upload 异步文件上传 `<progress min="0" max="100" value="0">0% complete</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.onloadstart:loadstart 事件(HTTP 请求发出)的监听函数 XMLHttpRequest.onprogress:progress事件(正在发送和加载数据)的监听函数 XMLHttpRequest.onabort:abort 事件(请求中止,比如用户调用了abort()方法)的监听函数 XMLHttpRequest.onerror:error 事件(请求失败)的监听函数 XMLHttpRequest.onload:load 事件(请求成功完成)的监听函数 XMLHttpRequest.ontimeout:timeout 事件(用户指定的时限超过了,请求还未完成)的监听函数 XMLHttpRequest.onloadend:loadend 事件(请求完成,不管成功或失败)的监听函数 ``` demo: ``` 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!'); }; ``` ## 实例方法 ### open() 初始化请求实例 ``` void open( string method, string url, optional boolean async, optional string user, optional string password ); ``` ### send() 实例发出http 发送的数据格式 其他参数类型 ``` void send(); void send(ArrayBufferView data); void send(Blob data); void send(Document data); void send(String data); void send(FormData data); ``` 如果为post ``` 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); ``` 发送表单 ``` var formData = new FormData(); formData.append('username', '张三'); formData.append('email', 'zhangsan@example.com'); formData.append('birthDate', 1940); var xhr = new XMLHttpRequest(); xhr.open('POST', '/register'); xhr.send(formData); ``` ### setRequestHeader 设置请求头 ``` xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Content-Length', JSON.stringify(data).length); xhr.send(JSON.stringify(data)); ``` ### overrideMimeType 覆盖原MIME的值 服务器返回的数据类型是`text/xml`,由于某种原因,解析不成功,为了拿到原始数据,我们可以把 MIME 类型改成`text/plain`,这样浏览器就不会解析,就可拿到原始数据 `xhr.overrideMimeType('text/plain') ### getResponseHeader 返回头字段信息 ``` var xhr = new XMLHttpRequest(); xhr.open('get','/test.php') xhr.onload=function (e) { console.log(this.getResponseHeader('Date')); } xhr.send(); ``` ### getResponseHeader() 返回所有都字段信息 ### abort() 禁止放请求 调用这个方法以后,`readyState`属性变为`4`,`status`属性变为`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 事件 此事件使用 `onreadyStateChange` 监听 ``` xhr.onreadystatechange=function () { console.log(xhr.readyState); } ``` ### 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 事件 ``` 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 事件 ``` xhr.addEventListener('timeout',function () { console.log('timeout'); }) xhr.timeout=100 ``` ### Navigator.sendBeacon() 卸载页面是发送数据 由于 `XMLHttpRequest` 不能保证发出清楚,使用这个方法 ``` window.addEventListener('unload', logData, false); function logData() { navigator.sendBeacon('/log', analyticsData); } ```