AJAX和XHR实现浏览器与服务器的异步通信

如今我们前端参与的项目大部分是前后端分离的项目,后端提供接口,前端调用接口,前端要完成客户端与服务器的数据交互(即:前后端的数据交互),如此JavaScript异步通信就非常重要,前端实现异步通信可以用AJAX代称。

AJAX不是一种编程语言,它是一种技术或者说一种方法,翻译过来是异步的 JavaScript 和 XML,AJAX是一种异步的客户端和服务端进行交换数据的方法,是在不刷新页面的情况下请求特定 URL,获取数据。
传统Ajax 指的是 XMLHttpRequest(XHR)目前常用的异步通信技术如JQuery的ajax,axios都是对XHR的二次封装,浏览器提供了一个构造函数XMLHttpRequest。
用XMLHttpRequest构造函数实例化一个XMLHttpRequest 对象,通过XMLHttpRequest 对象与服务器进行HTTP通信,同步或异步地返回 Web 服务器的响应,并以文本的形式返回内容。

PS:本文中说的XMLHttpRequest,指的是XMLHttpRequest Level 2,XMLHttpRequest Level 2 使用指南

下面我用fastmock模拟一个接口,演示一次异步HTTP请求

var xhr=new XMLHttpRequest();
xhr.open("GET","https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/getOne?id=1",true);
xhr.send();
xhr.onload =function(){
  console.log(xhr);
}

AJAX和XHR实现浏览器与服务器的异步通信_第1张图片

PS:
1、进行HTTP通信时,遵从HTTP协议,HTTP协议是超文本传输协议(HTTP,HyperText Transfer Protocol)是浏览器与Web服务器之间的应用层通信协议,HTTP协议交互的信息被称为HTTP报文
2、由于同源策略(基于浏览器的安全的一种约定),默认情况下浏览器不容许XMLHttpRequest进行跨域(协议、域名、端口只要有一个不同即是跨域)请求。

浏览器同源策略及跨域的解决方法

使用XmlHttpRequest对象发送一次ajax请求

一、创建XMLHttpRequest对象

在这里插入图片描述

XMLHttpRequest对象有个属性readyState在初次创建时为0,之后这个值随着交互的阶段不同会随时增加,readyState值的变化会触发onreadystatechange事件,当readyState值变为4时触发onload事件。

二、发送XMLHttpRequest请求

1、初始化 HTTP 请求参数

首先要用XMLHttpRequest对象的open()方法初始化 HTTP 请求参数,例如设置 URL 和 HTTP 方法,但并不发送请求。

xhr.Open(method,url,asynch,username,password)
参数 说明
method http请求的方法,最常用的是GET、POST、PUT、DELETE等,默认为GET
url 请求的服务器的地址,必选项
asynch 是否采用异步方法,布尔型,true为异步,false为同步,同步请求会阻塞js主线程,默认为false。
username 提供http认证机制需要的用户名
password 提供http认证机制需要的密码

常用的HTTP请求方法

2、为HTTP请求设置请求头

可以使用SetRequestHeader(header,Value)方法,为HTTP请求设置请求头,请求头包含了对客户端的环境描述、客户端请求的主机地址等信息。
设置HTTP请求中的指定头部header的值为value.
此方法需在open方法以后调用,一般在post方式中使用。

xhr.setRequestHeader("Cache-Control","no-cache");  //设置禁止缓存请求结果
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); // 设置客户端提交给服务器文本内容的编码方式

常用的HTTP请求头

3、发送请求

get请求

使用send(content)方法发送,GET请求没有主体,应传递null或省略参数

var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/getOne?id=1')
xhr.send()
xhr.onload = function () {
  console.log(xhr)
}

AJAX和XHR实现浏览器与服务器的异步通信_第2张图片

post请求

POST请求通常拥有主体,并必须使用setRequestHeader()指定“Content-Type”头

var xhr=new XMLHttpRequest();
xhr.open("POST","https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/add",true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 
xhr.send("id=1&title=标题");
xhr.onload =function(){
  console.log(xhr);
}

AJAX和XHR实现浏览器与服务器的异步通信_第3张图片

三、取得响应

XHR发送请求后,经过服务器的处理并返回数据成功的话,XMLHttpRequest对象status属性值一般是200,,readyState属性为4,并触发onload事件,这时候可以在XHR对象中取得服务器的响应数据。

var xhr=new XMLHttpRequest();
xhr.open("GET","https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/getOne?id=1",true);
xhr.send();
xhr.onload =function(){
  console.log(xhr)
  //http状态码为200,表示请求成功
  if(xhr.status == 200){
    console.log(JSON.parse(xhr.response));  //将json字符串解析成json对象
  }
}

打印出的XHR对象
AJAX和XHR实现浏览器与服务器的异步通信_第4张图片

与响应有关的属性
status和statusText

只读,status返回HTTP的响应状态码;statusText属性返回Http状态码的文本信息。
HTTP状态码详解

response、responseText和responseXML

只读,这三个属性返回的是服务器的响应数据。

  • response 可以返回一个 ArrayBuffer、Blob、Document、字符串,具体是哪种类型取决responseType 的值。
  • responseText返回一个字符串。
  • responseXML 返回一个 Document,其中包含该请求的响应,如果请求未成功、尚未发送或时不能被解析为 XML 或 HTML,则返回 null。
responseType

返回响应类型。允许我们手动的设置返回数据的类型。将它设置为一个空字符串,它将使用默认的"text"类型。

responseURL

只读,返回经过序列化的响应 URL,如果该 URL 为空,则返回空字符串。

打印出的响应数据
AJAX和XHR实现浏览器与服务器的异步通信_第5张图片

PS:虽然AJAX被称作异步的 JavaScript 和 XML,但是JSON字符串是数据交互时最常用的数据格式,不过,具体传递什么格式的数据要看前后端的约定。
JSON.parse()将JSON字符串转化为 js 对象

异常处理

现实中,不可能一直都是完美的http请求和响应,总会遇到各种各样的问题,比如服务器挂掉了,资源地址变化了,数据库出问题了,网络断了等等,这时候往往需要给用户一个反馈告知。
这里的异常指的是HTTP连接异常,而不是应用的数据异常,也就是与HTTP状态码有关的异常。

1、超时

在下面的test.php中,我设置2秒后返回结果,js代码设置xhr.timeout = 1000,这样请求就会超时,进而触发ontimeout事件,超时时服务器没有响应。

var xhr=new XMLHttpRequest();
xhr.open("GET","http://localhost:8081/test.php",true);
xhr.timeout = 1000;
xhr.send();

xhr.ontimeout = function () {
  console.log('您的请求超时了');
};

2、abort()方法

abort()方法用于终止已经发出的请求,readyState 属性将被置为0

5、upload属性

XMLHttpRequest.upload 属性返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。

XMLHttpRequest对象的事件

onreadystatechange

onreadystatechange属性存储一个函数,每当 readyState 属性改变时,就会调用该函数。所以也叫onreadystatechange事件。可以为onreadystatechange事件绑定处理函数或者监听事件。

var xhr=new XMLHttpRequest();
//readyState值的变化会触发onreadystatechange事件
xhr.onreadystatechange = function(){
  console.log('readyState属性:',xhr.readyState)
};
xhr.open("GET","https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/getOne?id=1",true);
xhr.send();
//请求成功时触发,此时readystate为4
xhr.onload=function(){
  console.log('onload事件:readyState属性:',xhr.readyState)
};

AJAX和XHR实现浏览器与服务器的异步通信_第6张图片

和onreadystatechange属性相似的还有事件:

事件 触发条件
onreadystatechange readyState改变时触发;但readyState由非0值变为0时不触发。
onloadstart 开始发出请求时触发(end()方法后立即触发)
onprogress 服务器已经响应,等待处理时周期性地触发
onload 当请求成功时触发,此时readystate为4
onloadend 当请求结束(包括请求成功、失败、终止)时触发
onabort 终止请求时触发,如调用xhr.abort()后触发
ontimeout xhr.timeout不等于0,由请求开始即onloadstart开始算起,当到达xhr.timeout所设置时间请求还未结束即onloadend,则触发此事件。
onerror 请求错误时触发;在请求过程中,若发生Network error则会触发此事件(若发生Network error时,上传还没有结束,则会先触发

XMLHttpRequest对象详解

使用FormData对象收集表单数据

XMLHttpRequest Level 2定义了 FormData 类型用以将表单数据序列化,以便用XMLHttpRequest来发送数据。
AJAX和XHR实现浏览器与服务器的异步通信_第7张图片
通过上图可以看到FormData对象没有实例属性,可以用的都是一些原型方法,一般使用FormData对象有两种方式:

创建一个空FormData对象

var formData = new FormData()
formData.append("userName", 'admin')
formData.append("familyMembers", 'mother')
formData.append("familyMembers", 'father')
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:5002')
xhr.onload = function () {
    console.log(JSON.parse(xhr.response))
  }
xhr.send(formData)

AJAX和XHR实现浏览器与服务器的异步通信_第8张图片

通过已有表单来初始化对象FormData对象

<form method="post" id="myForm">
    <input type="text" name="userName" >
    <input type="checkbox" name="familyMembers" value="mother" >mother
    <input type="checkbox" name="familyMembers" value="father" >father
    <input type="button" value="提交" id="btn">
form>
<script>
var myForm = document.getElementById('myForm')
var btn = document.getElementById('btn')
btn.onclick = function () {
  var formData = new FormData(myForm)
  formData.get('userName')
  formData.get('familyMembers')
  const xhr = new XMLHttpRequest()
  xhr.open('POST', 'http://localhost:5002')
  xhr.onload = function () {
    console.log(JSON.parse(xhr.response))
  }
  xhr.send(formData)
}
script>
  • 使用FormData收集表单数据提交给服务器,不能使用 GET请求,因为 GET请求会忽略请求体
  • 浏览器会自动识别并添加请求头 “Content-Type: multipart/form-data”,并加入boundary,如果手动设置,浏览器不会生成boundary,后端将无法解析。
  • FormData 的最大优点就是我们可以异步上传文件。

FormData对象详解

使用FormData对象异步上传文件

要实现上传文件,需要一个文件域 file
[](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file)元素详解使用户可以选择一个或多个元素以提交表单的方式上传到服务器上。

<input type="file" id="files"/>
<script>
var input = document.getElementById('files')
input.addEventListener('change', function () {
  const formData = new FormData()
  formData.append('id', 1)
  formData.append('file', input.files[0])
  const xhr = new XMLHttpRequest()
  // 要在open方法前添加事件监听
  xhr.upload.onprogress = function (event) {
    if (event.lengthComputable) {
      var percentComplete = Math.round(event.loaded / event.total * 100)
      console.log(new Date().getTime(), percentComplete + '%')
    }
  }
  xhr.open('POST', 'http://localhost:5002/upload')
  xhr.onload = function () {
    console.log(JSON.parse(xhr.response))
  }
  xhr.send(formData)
})
script>

AJAX和XHR实现浏览器与服务器的异步通信_第9张图片

上传文件相关属性

upload 属性,返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。

事件 相应属性的信息类型
onloadstart 获取开始
onprogress 在上传阶段(即xhr.send()之后周期性触发
onabort 获取操作终止
onerror 获取失败
onload 获取成功
ontimeout 获取操作在用户规定的时间内未完成
onloadend 获取完成(不论成功与否)

通过XHR接收二进制数据

XMLHttpRequest Level 2可以取回二进制数据,常用于下载文件,接收二进制数据时,需要设置配置XHR属性responseType为“blob”或“arraybuffer”。
下面的两个例子分别用这两个方法从服务器请求一个二进制的数据并下载到本地,涉及到的Blob对象和
ArrayBuffer对象可以参考Javascript操作文件

  • responseType为“blob”,请求的response会被转为Blob对象
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://localhost:5002/download')
    xhr.responseType = 'blob'
    xhr.onload = function () {
      console.log(xhr)
      var aEle = document.createElement('a')
      aEle.download = 'demo'
      aEle.href = URL.createObjectURL(xhr.response)
      aEle.click()
    }
    xhr.send()
    
    在浏览器Network面板中可以看到返回的如下二进制数据
    AJAX和XHR实现浏览器与服务器的异步通信_第10张图片
    AJAX和XHR实现浏览器与服务器的异步通信_第11张图片
  • responseType为“arraybuffer”,请求的response会被转为ArrayBuffer对象(类似数组)
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://localhost:5002/download')
    xhr.responseType = 'arraybuffer'
    xhr.onload = function () {
      console.log(xhr)
      var binary = ''
      var buffer = xhr.response
      var bytes = new Uint8Array(buffer)
      for (var i = 0; i < bytes.length; i++) {
        binary += String.fromCharCode(bytes[i])
      }
      var src = window.btoa(binary)
      var aEle = document.createElement('a')
      aEle.download = 'demo'
      aEle.href = 'data:image:png,base64' + src
      aEle.click()
    }
    xhr.send()
    
    AJAX和XHR实现浏览器与服务器的异步通信_第12张图片

你可能感兴趣的:(前端进阶之路,Javascript)