JS之AJAX-XHR对象

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

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

  • 创建XMLHttpRequest对象

  • 发送HTTP请求

  • 接收服务器返回的数据

  • 更新网页数据

创建

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

var xhr = new XMLHttpRequest()

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

这里也可以做一下兼容:

if (window.XMLHttpRequest) {
    xhr = new window.XMLHttpRequest;
} else {
    xhr = new ActiveXObject("Microsoft.XMLHTTP");
}

发送请求

open()

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

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()方法的参数为要发送的数据

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

接收响应

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

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冻结,如果连接的服务器响应慢,那么用户的浏览器将冻结

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

<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属性,该属性表示请求/响应过程的当前活动阶段,取值如下:

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

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

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

异步请求示例

<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事件

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中请求后端方法中部分代码:

 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() 方法:

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

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

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