让大家都能理解 XMLHttpRequest

  XMLHttpRequest 是一个 JavaScript 对象,它能够在浏览器和 Web 服务器之间发送和接收数据。即使在从 Web 服务器读取了所有数据之后,XMLHttpRequest 仍然可以发送和接收数据,从而实现不重新加载页面就能够重写页面内容的功能。在当今的 Web 服务中,使用 XMLHttpRequest 发送和接收数据是非常必要的。尽管现在使用XMLHttpRequest 直接与Web服务器收发数据的机会不多,大多数情况下都是使用 axios(底层使用 XMLHttpRequest)和 fetch 函数。但是,理解 XMLHttpRequest 对于理解这些技术仍然非常重要,因此我们应该深入了解它。

  • 让大家都能理解 XMLHttpRequest
    • 1 XMLHttpRequest使用
    • 2 XMLHttpRequest 处理流程
    • 3 onreadystatechange 事件
    • 4 接收 JSON 数据
    • 5 响应类型
    • 6 XMLHttpRequest其他事件
    • 7 FormData 请求

1 XMLHttpRequest使用

以下是使用 XMLHttpRequest 的 JavaScript 代码,它应该写在脚本标签中:

<script>// (1)XMLHttpRequest对象创建var xmlHttpRequest = new XMLHttpRequest();// (2)onreadystatechange监听请求的状态xmlHttpRequest.onreadystatechange = function(){    if(this.readyState == 4 && this.status == 200){        console.log(this.responseText);    }}// (3)HTTP通过GET服务路径与服务器进行通信xmlHttpRequest.open(  'GET',  'https://jsonplaceholder.typicode.com/users/1',  true);// (4)HTTP中发生信息xmlHttpRequest.send();</script>

我们可以使用 https://jsonplaceholder.typicode.com/ URL 来进行测试,它是一个公共的网络测试资源地址,专门用于测试。如果您不想搭建自己的服务器,可以尝试使用它来进行 Ajax 路径测试。

2 XMLHttpRequest 处理流程

(1) 创建一个XMLHttpRequest对象

var xmlHttpRequest = new XMLHttpRequest();

创建 XMLHttpRequest 实例,使用该实例可以在浏览器和服务器之间进行通信。

(2)用onreadystatechange事件监听请求状态

xmlHttpRequest.onreadystatechange = function(){    if(this.readyState == 4 && this.status == 200){        console.log(this.responseText);    }}

  可以使用 onreadystatechange 事件来监视 XMLHttpRequest 处理状态的变化。该事件用于监视状态的变化,以便可以检测来自服务器的响应(即接收到的数据)何时完成。此外,还可以通过确认响应的 HTTP 状态代码是否为 200,来确定请求是否成功。

readyState 被分配一个从 0 到 4 的数字,代表处理的状态,其中 4 代表请求处理完成。如果 readyState 为 4,状态码为 200,则可以使用 console.log 命令打印接收到的数据。

由于 XMLHttpRequest 与服务器进行异步通信,与等待同步处理完成不同,您不知道何时处理完成。因此,我们需要使用 onreadystatechange 事件来监视处理状态,并采取适当的措施。

使用该事件,可以在请求的处理过程中多次检查 readyState 的值,并据此采取必要的操作,以确保在处理完成时能够得到所需的结果。

(3)指定HTTP GET方法和访问位置

xmlHttpRequest.open(  'GET',  'https://jsonplaceholder.typicode.com/users/1',  true);

第三个参数 true 是异步设置。如果异步则设置为 true,如果同步则设置为 false。

XMLHttpRequest.open('HTTP类型','URL',['async',user,password])

如果要进行异步通信,则应将 async 参数设置为 true,如果要进行同步通信,则应将其设置为 false。在使用 open 方法时,还可以指定用户和密码,以进行基本身份验证。

(4) 发送HTTP请求

xmlHttpRequest.send();

发送请求到服务器然后等待服务器的响应。我们可以使用 (2) 中的事件来检查服务器的响应是否完成。

3 onreadystatechange 事件

在ajax请求的时候每当处理状态发生变化时,都会产生 readystatechange 事件,以便代码可以相应地处理变化。当前状态可以通过 readyState 属性进行判断。readyState 属性被分配了 0 到 4 之间的值,并且含义因数字而异。

  • readyState=0 : status=UNSENT: 初始状态(实例创建)
  • readyState=1 : status=OPENED: 打开方法执行
  • readyState=2 : status=HEADERS_RECEIVED: 收到响应头
  • readyState=3 : Status=LOADING: 正在接收数据
  • readyState=4 : status=DONE: 请求完成

使用下面的代码检查每次进程状态更改时是否实际触发了 onreadystatechange 事件。除了 onreadystatechange 事件外,其余的代码与前面解释的代码相同。

xmlHttpRequest.onreadystatechange = function(){       if(this.readyState == 0){        console.log('UNSENT:初始状态')    }                if(this.readyState == 1){        console.log('OPENED: 打开方法执行')    }                if(this.readyState == 2){        console.log('HEADERS_RECEIVED:收到响应头')    }                if(this.readyState == 3){        console.log('LOADING:正在接收数据')    }    if(this.readyState == 4){        console.log('DONE: 请求完成')    }}

4 接收 JSON 数据

在与服务器进行通信时,大多数情况下数据都是以 JSON 格式发送的。我们可以将服务器返回的数据转换为 JSON 格式。请注意,服务器端的处理因环境而异,返回的数据格式有所不同。但是我们大多数情况使用 Spring Boot 作为服务端,因此返回的数组会自动转换为 JSON 格式。

xmlHttpRequest.onreadystatechange = function(){    if(this.readyState == 4 && this.status == 200){        user = JSON.parse(this.responseText);        console.log(user)    }}

如果this.responseText返回的数据是以字符串形式的 JSON 数据传输的,我们需要使用JSON.parse()方法将其解析成一个 JavaScript 对象。如果不进行转换,该数据可能会被解释为 undefined。

5 响应类型

如果你设置了 Response Type 为 JSON,那么可以直接获取响应数据的格式。因此,不需要再运行 JSON.parse 将其转换为对象。不过,需要注意的是,在获取值时,应该使用 response 属性,而不是 responseText。

var xmlHttpRequest = new XMLHttpRequest();xmlHttpRequest.responseType = 'json';xmlHttpRequest.onreadystatechange = function(){    if(this.readyState == 4 && this.status == 200){        //responseType = 'json' 不能使用this.responseText         //直接使用 response        user = this.response;        console.log(user)    }}

使用 getAllResponseHeaders() 检查来自服务器的响应标头信息。

var xmlHttpRequest = new XMLHttpRequest();xmlHttpRequest.responseType = 'json';xmlHttpRequest.onreadystatechange = function(){    if(this.readyState == 4 && this.status == 200){        //responseType = 'json' 不能使用this.responseText         //直接使用 response        user = this.response;        console.log(user);        console.log(this.getAllResponseHeaders());    }}

6 XMLHttpRequest其他事件

我们使用 onreadystatechange 事件来检查处理状态,除了 onreadystatechange 事件之外,还有以下事件可以使用。

  • onloadstart :请求开始时
  • onprogress :定期运行,直到请求完成。也可以检查接收到的数据。
  • onabort :当请求被 abort 方法中止时
  • onerror : 当请求发生错误时
  • onload :请求完成时
  • ontimeout :请求超时时

设置以下 6 个事件并检查它们是被执行正常工作。

xmlHttpRequest.onloadstart = function(){    console.log('onloadstart请求开始时');};xmlHttpRequest.onprogress = function(){    console.log('onprogress事件');};xmlHttpRequest.onload = function(){    console.log('onload事件');};xmlHttpRequest.onabort = function(){    console.log('onabort事件');};xmlHttpRequest.onerror = function(){    console.log('onerror事件');};xmlHttpRequest.ontimeout = function(){    console.log('ontimeout事件');};

我们可以看到浏览器GET请求成功完成后只执行了以下3个事件。

onloadstart请求开始时onprogress事件onload事件

abort 事件触发条件,只有在XMLHttpRequest在代码中设置abort方法,并且使用它。发送数据后立即执行 abort 方法,才会执行abort 事件。

xmlHttpRequest.send();xmlHttpRequest.abort();

这样才可以看到在启动请求的 onloadstart 之后触发了 onabort 事件。

接下样我们看看超时事件 ontimeout 触发条件。设置请求超时。由于单位是毫秒,如果请求后2000(=2秒)服务器没有响应,就会执行事件。

xmlHttpRequest.timeout = 2000

onerror 事件 触发条件是,访问了服务器端一个不存在的IP地址,onerror 事件才会发生。

xmlHttpRequest.open('GET','http://127.0.0.100',true);

我发现可以在 onerror 事件中检查网络级错误。当收到 404 错误,这意味着你能够与服务器通信,但是页面不存在。在这种情况下,我们可以在执行的 onload 事件中进行检查。当程序执行 onload 事件时,也会显示HTTP状态码,返回状态码404和Not Found404。

xmlHttpRequest.onload = function(){    console.log('onload事件');    //状态    console.log(this.status);};

我们可以使用HTTP状态代码来判断是否发生了HTTP级别的错误。如果状态代码不是正常的200,就可以终止程序的运行;否则,程序可以继续运行。我们通常会使用它来处理 404 以及服务器的 Eroro 500错误。

xmlHttpRequest.onload = function(){    if(this.status != 200){    console.log(this.status + ':程序终止运行。');    }else{        console.log(this.status + '正常运行。');    }};

7 FormData 请求

下面是用于向服务器异步发送数据的 JavaScript 代码。

<script>    // (1)XMLHttpRequest创建实例    var xmlHttpRequest = new XMLHttpRequest();    // (2)HTTP的POST请求    xmlHttpRequest.open('POST','/api/onsave',true);    // (3)数据发送的格式类型    xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');    // (4)HTTP发送的数据    xmlHttpRequest.send('id=2&name=zht');</script>

步骤(3)的设置是指定要发送的数据的格式。这次发送数据的格式是key1=value1&key2=value2,所以Content-Type要设置成application/x-www-form-urlencoded。如果不指定数据格式,在服务器端可能无法正常的接收数据。

大多数的时候我们会使用 FormData 对象发送数据。让我们看看FormData 是如何发送数据的。

var xmlHttpRequest = new XMLHttpRequest();var formData = new FormData();formData.append("id", 3);formData.append("name","zht");xmlHttpRequest.open('POST','/api/onsave',true);xmlHttpRequest.send(formData);

代码中使用 FormData 的 append 方法添加要发送的数据。此外,使用 FormData发送数据在代码中不需要设置内容类型setRequestHeader 。

通过下面的例子让我们看看在html代码中如何使用FormData将form数据发送到服务端的。

<form name="user">    Id:<input type="text" name="id"><br>    名称:<input type="text" name="name"><br>    <input type="submit" onclick="sendPost();return false;">添加</button></form>

创建 sendPost 函数,该函数内部使用 document.forms.user 方法将表单的内容放入 FormData 对象中。通过发送 FormData 对象,将输入表单的内容发送到服务器(使用 POST 请求方式)。

function sendPost(){    var xmlHttpRequest = new XMLHttpRequest();    var formData = new FormData(document.forms.user);    xmlHttpRequest.open('POST','/api/onsave',true);    xmlHttpRequest.send(formData);}