JS之AJAX-XHR对象

AJAX是Asynchronous JavasSript And XML的简写,这项技术能够在不卸载页面的情况下发出HTTP请求,虽然名字中包含XML,但AJAX通信与数据格式无关

AJAX通信通常包含4个步骤:

  • 创建XMLHttpRequest对象

  • 发送HTTP请求

  • 接收服务器返回的数据

  • 更新网页数据

创建

AJAX技术的核心是XMLHttpRequest对象(简称XHR),可以直接使用new关键字实例化一个XHR对象

  [js]
1
var xhr = new XMLHttpRequest()

注意: 如果要建立N个不同的请求,理论上需要使用N个不同的XHR对象。如果重用已存在的XHR对象,会终止之前通过该对象挂起的任何请求

这里也可以做一下兼容:

  [js]
1
2
3
4
5
if (window.XMLHttpRequest) { xhr = new window.XMLHttpRequest; } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }

发送请求

open()

XHR对象的open()方法用于发送请求,该方法接收三个参数:请求方式、请求地址和一个布尔值

  [js]
1
xhr.open("GET","/api/test", true);

请求方式:请求方式比较常用的是GET和POST,也可以是PATCH、DELETE、OPTIONS等。这个字符串是不区分大小写的,但通常使用大写字母。

请求地址:请求地址通常是相对于执行代码的当前页面。

如果需要发出跨域请求,后端要支持CORS,否则会报错

布尔值:布尔值表示是否异步发送请求的布尔值,默认为true,表示异步发送

其他:如果请求一个受密码保护的URL,可以把用于认证的用户名和密码作为第4和第5个参数传递给open()方法

send()

open()方法调用后,必须执行send()方法才会真正发送请求。

如果是GET方式,send()方法无参数,或参数为null;如果是POST方式,send()方法的参数为要发送的数据

  [js]
1
2
xhr.open('GET', 'https://www.86886.wang/api/tags', true); xhr.send(null);

接收响应

一个完整的HTTP请求由响应状态码、响应头集合和响应主体组成。在收到响应后,这些都可以通过XHR对象的属性和方法使用,主要有以下4个属性

  [plaintext]
1
2
3
4
responseText: 作为响应主体被返回的文本(文本形式) responseXML: 如果响应的内容类型是'text/xml'或'application/xml',这个属性中将保存着响应数据的XML DOM文档(document形式) status: HTTP状态码(数字形式),比如200 statusText: HTTP状态说明(文本形式),比如OK

在接收到响应后,第一步是检测status状态,HTTP状态码为200表示请求成功,此时responseText属性的内容已经就绪。

另外状态码304表示资源没有被修改,可以直接从浏览器缓存获取,这个响应也是有效的

无论内容类型是什么,响应主体的内容都会保存到responseText属性中。

对于非XML数据而言(如JSON),responseXML属性的值将为null

  [js]
1
2
3
4
5
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); }else{ console.log('Request fail:' + xhr.status); }

同步请求

把open()方法的第三个参数设置为false,表示是同步请求,此时send()方法将会阻塞直到请求完成。

由于JS是单线程的,所以会导致整个浏览器UI冻结,如果连接的服务器响应慢,那么用户的浏览器将冻结

开发中要避免使用同步请求,下面是同步请求的示例

  [html]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="result"></div> <button id="btn">GET同步请求</button> <script> btn.onclick = function() { var data = ajax(); result.innerHTML = data; } function ajax() { var xhr = new XMLHttpRequest(); if(xhr.readyState == 4) { if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ return xhr.responseText; } } // 同步请求 xhr.open('GET', 'https://www.86886.wang/api/tags', false); xhr.send(); } </script>

异步请求

异步请求需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段,取值如下:

  [plaintext]
1
2
3
4
5
0(UNSENT):未初始化。尚未调用open()方法 1(OPENED):启动。已经调用open()方法,但尚未调用send()方法 2(HEADERS_RECEIVED):发送。己经调用send()方法,且接收到头信息 3(LOADING):接收。已经接收到部分响应主体信息 4(DONE):完成。已经接收到全部响应数据,而且已经可以在客户端使用了

只要readyState属性值发生变化,就会触发onreadystatechange事件,通常只需要对值为4时做判断,此时表示数据已经准备就绪

注意: 必须在调用open()之前指定onreadystatechange 事件处理程序才能确保跨浏览器兼容性,否则将无法接收readyState属性为0和1的情况

异步请求示例

  [html]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="result"></div> <button id="btn">GET异步请求</button> <script> btn.onclick = function() { ajax(function(data) { result.innerHTML = data; }); } function ajax(cb) { var xhr = new XMLHttpRequest(); // 异步请求 xhr.onreadystatechange = function() { if(xhr.readyState == 4) { if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ cb(xhr.responseText); } } } xhr.open('GET', 'https://www.86886.wang/api/tags', true); xhr.send(); } </script>

超时

XHR对象有一个timeout属性,表示多少毫秒后,如果请求仍然没有得到结果就会自动终止。默认值0,表示没有限制

如果请求超时,会触发ontimeout事件

  [js]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function ajax(cb) { var xhr = new XMLHttpRequest(); // 异步请求 xhr.onreadystatechange = function() { if(xhr.readyState == 4) { if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ cb(xhr.responseText); } } } xhr.open('GET', 'https://www.86886.wang/api/tags', true); xhr.ontimeout = function() { console.log('The request timed out.'); } xhr.timeout = 5000; // 5s xhr.send(); }

数据传输

form 表单

html中请求后端方法中部分代码:

  [js]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
onSubmit:function(){ var xhr = function () { if(window.XMLHttpRequest){ return new XMLHttpRequest(); }else{ return new ActiveXObject("Microsoft.XMLHTTP");// IE6, IE5 浏览器执行代码 } }(); xhr.onreadystatechange = function () { switch(xhr.readyState){ case 0: console.log(0,'未初始化...'); break; case 1: console.log(1,'请求参数已准备,尚未发送请求...'); break; case 3: console.log(3,'已接收数据长度:'+xhr.responseText.length); break; case 4: console.log(4,'响应全部接受完毕'); if((xhr.status >=200 && xhr.status < 300) || xhr.status ==304){ var databox = xhr.responseText; console.log(databox) }else{ console.log('error:'+ xhr.status) } break; } } var data = this.encodeFormData({ articleTxt:this.articleTxt.innerHTML, //富文本内容 title: this.title //标题 }); xhr.open('POST','http://localhost:99/formdata',true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //formdata数据请求头需设置为application/x-www-form-urlencoded xhr.send(data); }

JSON

JSON和JS对象的互转

要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法:

  [js]
1
2
var obj = JSON.parse('{"a": "Hello", "b": "World"}') //结果是 {a: 'Hello', b: 'World'}

要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify() 方法:

  [js]
1
2
var json = JSON.stringify({a: 'Hello', b: 'World'}) //结果是 '{"a": "Hello", "b": "World"}'

参考资料

JS之AJAX-XHR对象

https://blog.csdn.net/lianghecai52171314/article/details/103095814

http://t.zoukankan.com/ellen-mylife-p-11720671.html

用js原生的xhr请求后端+nodeJs后端接口实现

前后端交互 —— 04ajax 之XHR + 数据交换格式JSON