ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 一、 同步限制 XMLHttpRequest(简称xhr)常用的都是异步请求数据,但xhr也可以同步请求数据,但在同步的时候,有些参数必须按要求来限制如下: xhr.tiemout必须为0 xhr.withCredentials必须为0 xhr.responseType必须为""("text"都不允许) 同步的进候send是阻塞的,此时的xhr.readstate由2变成3,且onreadystatechange事件不为触发,xhr.upload.onprogress和xhr.onprogress事件也不会触发。。 ## 二 、send xhr.send(data)的参数类型可以为: * ArrayBuffer * Blob * Document(content-type: text/html;charset=utf-8) * DOMString(content-type: text/plain;charset=utf-8) * FormData(content-type: multipart/form-data;boundary=[xxx]) * null 使用图解: ![](https://box.kancloud.cn/a0b332d07bf9ad0b9c18594041e07a77_732x482.jpg) 以FormData为例: ~~~ function sendAjax() { //构造表单数据 var formData = new FormData(); formData.append('username', 'johndoe'); formData.append('id', 123456); //创建xhr对象 var xhr = new XMLHttpRequest(); //设置xhr请求的超时时间 xhr.timeout = 3000; //设置响应返回的数据格式 xhr.responseType = "text"; //创建一个 post 请求,采用异步 xhr.open('POST', '/server', true); //注册相关事件回调处理函数 xhr.onload = function(e) { if(this.status == 200||this.status == 304){ alert(this.responseText); } }; xhr.ontimeout = function(e) { ... }; xhr.onerror = function(e) { ... }; xhr.upload.onprogress = function(e) { ... }; //发送数据 xhr.send(formData); } ~~~ ## 三、事件的触发顺序 * 1、触发xhr.onreadystatechange(这后每次readystate变化时,都会触发一次) * 2、触发xhr.onloadstart // 上传阶段 * 3、触发xhr.upload.onloadstart * 4、触发xhr.upload.onprogress * 5、触发xhr.upload.onload * 6、触发xhr.upload.onloadend // 上传结束,下载阶段 * 7、触发xhr.onprogress * 8、触发xhr.onload * 9、触发xhr.onloadend ## 四、示例 **1、post请求** html ~~~ <input name="username" type="input" /> <input name="password" type="input" /> <button type="button">提交数据</button> ~~~ js ~~~ var $ = document.querySelector.bind(document); // 点击提交 $('button').addEventListener('click', handelXhr, false); // useCapture:true(捕获阶段) false(冒泡阶段-默认) // 处理xhr function handelXhr() { var xhr = new XMLHttpRequest(); xhr.open('post', 'test.php', true); // true表示异步,false表示同步 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); // 模拟form提交,别写错了 var data = { username: $('[name="username"]').value, password: $('[name="password"]').value }; xhr.send('username='+data.username+'&password='+data.password); // 每当 readyState 属性改变时,就会调用onreadystatechange函数 xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) { console.log(JSON.parse(xhr.responseText)) } } } ~~~ 低版本IE(IE5、IE6)觉得就没必要记了,像淘宝、京东已经不支持IE7以下的浏览器了 ~~~ if(window.ActiveXObject) { // IE5、IE6的写法 new ActiveXObject("Microsoft.XMLHTTP"); } ~~~ php ~~~ <?php echo json_encode($_POST); // 也可以使用file_get_contents('php://input', 'r')获取整个send ?> ~~~ 结果 ![](https://box.kancloud.cn/f9fd3f4b1c6a2b4e01e862354f7567f5_341x124.jpg) 下面看下readyState的5种状态 | 状态码 | 状态描述 | | --- | --- | | 0 | 请求未初始化 | | 1 | 服务器连接已建立 | | 2 | 请求已接收 | | 3 | 请求处理中 | | 4 | 请求已完成,且响应已就绪 | 在看下status状态 | 状态码 | 状态描述 | | --- | --- | | 200 | OK | | 404 | 未找到页面 | 事件 | 事件 | 描述 | | --- | --- | | onabort | 当请求中止时触发 | | onload | 当请求成功时触发 | | onloadend | 在请求成功或者失败时触发;load、abort、error、timeout事件发生之后 | | onloadstart | 当请求开始时触发 | | onreadystatechange | 当readyStateChange属性改变时触发 | | ontimeout | 当timeout属性指定的时间已经过去但响应依旧没有完成时触发 | | onerror | 当请求因错误失败时触发。注意404等状态码不是error,因为此时响应仍然是成功完成的 | | onprogress | 当响应主体正在下载重复触发(约每隔50ms一次) | **2、get请求** js ~~~ function handelXhr() { var data = { username: $('[name="username"]').value, password: $('[name="password"]').value }; var xhr = new XMLHttpRequest(); xhr.open('get', 'test.php?username='+data.username+'&password='+data.password, true); // true表示异步,false表示同步 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); // 模拟form提交,别写错了 xhr.send(null); // 每当 readyState 属性改变时,就会调用onreadystatechange函数 xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) { console.log(JSON.parse(xhr.responseText)) } } } ~~~ php ~~~ <?php echo json_encode($_GET); ~~~ get和post的区别就是传递参数的方式不一样 **3、使用loading** 先看下XMLHttprRequest对象都有哪些属性和方法 ![](https://box.kancloud.cn/47dc751dd30c00e9128d36259c904f48_472x410.jpg) 从中可以找到onprogress方法和onload方法 ~~~ function handelXhr() { var data = { username: $('[name="username"]').value, password: $('[name="password"]').value }; var xhr = new XMLHttpRequest(); xhr.open('get', 'test.php?username='+data.username+'&password='+data.password, true); // true表示异步,false表示同步 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); // 模拟form提交,别写错了 xhr.send(null); // 加载中 var p = document.createElement('p'); xhr.onprogress = function() { p.innerHTML = '加载中...'; $('body').appendChild(p); } // 每当 readyState 属性改变时,就会调用onreadystatechange函数 xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) { console.log(JSON.parse(xhr.responseText)); // $('body p').parentNode.removeChild(p); 也可以在这里删除 } } // 加载完成 xhr.onload = function() { $('body p').parentNode.removeChild(p); } } ~~~ **4、超时设置** ~~~ xhr.timeout = 10000; // 10秒 xhr.ontimeout = function() { console.log('请求超时'); } ~~~ **5、取消请求** ~~~ xhr.abort(); ~~~ **6、withCredentials** 默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。 ~~~ Access-Control-Allow-Credentials: true ~~~ 如果发送的是带凭据的请求,但服务器的相应中没有包含这个头部,那么浏览器就不会把相应交给JavaScript(于是,responseText中将是空字符串,status的值为0,而且会调用onerror()事件处理程序)。另外,服务器还可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求。 支持withCredentials属性的浏览器有Firefox 3.5+、Safari 4+和Chrome。IE10及更早版本都不支持。 **7、responseType** | 类型 | 描述 | | --- | --- | | "" | DOMString (默认值) | | arraybuffer | ArrayBuffer | | blob | Blob | | document | document | | json | JSON | | text | DOMString | ~~~ // responseType=json示例 function handelXhr() { var data = { username: $('[name="username"]').value, password: $('[name="password"]').value }; var xhr = new XMLHttpRequest(); xhr.open('get', 'test.php?username='+data.username+'&password='+data.password, true); xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); xhr.responseType = 'json'; xhr.send(null); xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) { console.log(xhr.response); } } } ~~~ 简单封装 ~~~ function ajax(options) { var defaults = { type: 'get', url: '', isAsync: true, data: null, success: function() {}, error: function() {}, complete: function() {} }; var conf = Object.assign({}, defaults, options); var xhr = new window.XMLHttpRequest(); xhr.open(conf.type, conf.url, conf.isAsync); xhr.send(conf.data); // 状态改变 xhr.onreadystatechange = function() { if(this.readyState!=4 || this.status!=200) { // 添加loading } else { // 删除loading } } // 请求成功 xhr.onload = function() { if(this.readyState==4 && this.status==200) { conf.success.call(null, this.response, this); } }; // 失败 xhr.onerror = function() { conf.error.call(this); }; // 加载结束,不管成功还是失败 xhr.onloadend = function() { conf.complete.call(this); }; } // 调用 ajax({ url: 'demo.php', success: function(data) { console.log(JSON.parse(data)); }, error: function() { alert('失败'); }, complete: function() { alert('完成'); } }); ~~~ ## 六、jquery相关封装 ~~~ var data = { username: $('[name="username"]').value, password: $('[name="password"]').value }; $.ajax({ type: 'get', url: 'test.php', data: data, beforeSend: function() { // 发送前 // 显示loading层 }, success: function(res) { // 成功 console.log(res); // 隐藏loading层 }, error: function() { // 报错 console.log('请求出错'); }, complete: function() { // 成功/报错 console.log('完成~'); } }); ~~~ 除此还有 ~~~ $.post(url , [data], [callback], [type]); ~~~ ~~~ $.get(url , [data], [callback], [type]); ~~~ 这里的type可以为:xml, html, script, json, text, _default,是jquery封装好的responseType ## 七、跨域 **1、后台添加如下代码** ~~~ header( 'Access-Control-Allow-Origin:*' ); ~~~ **2、使用jsonp** 原理在地址中添加url?callback=handel,然后页面调用handel函数,如: ~~~ handel({"username":"1","password":"2"}) ~~~ 下面是请求截取的字段也可以看出 ~~~ // Request URL:http://localhost/test/test.php?call=handel // Query String Parameter // call:handel ~~~ 示例: js ~~~ function callback(res) { console.log(res); } $.ajax({ type: 'get', url: 'demo.php', dataType: 'jsonp' }); ~~~ php ~~~ $a = array('name'=>'tom','age'=>23); echo 'callback('.json_encode($a).')'; ~~~ 自定义请求参数名和回调函数名 js ~~~ function handel(res) { console.log(res); } $('button').click(function() { $.ajax({ type:'post', url: 'test.php', data: {username: 'tom', password: '123456'}, dataType: 'jsonp', jsonp: 'call', jsonpCallback: 'handel' }); }); ~~~ php ~~~ echo $_GET['call'].'('.json_encode($_POST).')'; ~~~