XHR与FETCH-基于HTTP实现的AJAX(四)

234 阅读4分钟

基于HTTP的AJAX

AJAX应该是每一个前端开发者都必备的知识,在现代的网页中AJAX被广泛的应用,在开发或使用的过程中不难发现我们在编辑发送一个AJAX的请求其实就是在创建一个HTTP报文(还不了解HTTP协议可参考HTTP-互联网数据传输的基石(三) - 掘金 (juejin.cn)),其请求与响应正是HTTP通信的过程。如今我们常用的AJAX请求的工具有Axios与Fetch,而Axios则是基于 XHR 进行封装优化完善的一个工具库,Fetch为ES6新引入的API。

XHR与FETCH

当初,AJAX(Asynchronous JavaScript and XML)这一术语主要用于描述使用XMLHttpRequest(XHR)对象进行的异步数据交换过程。但随着Web开发技术的不断进步,Fetch API作为一种更加现代、简洁且功能强大的方法被引入,用于执行异步HTTP请求。与XHR相比,Fetch API采用了Promise对象来处理请求和响应,使得异步操作的编写更为直观和优雅。Fetch API不仅简化了代码,还提供了更好的错误处理机制,并支持更多的HTTP方法等。如今XHR官方已经停止维护,而Fetch还在持续维护中。。。

XMLHttpRequest

是一个出现比较早的发送AJAX请求的API,正因如此它在开发使用过程中有较好的兼容性与稳定性。其之所以可以异步的获取资源本质就是进行了HTTP通信,下面就以HTTP的通信过程来了解一下XHR。

使用XHR进行HTTP通信

  1. 创建XHR实例
const xhr = new XMLHttpRequest()
  1. 设置请求信息
// xhr.open(method,url,isAsync)接收三个参数分别是请求的方法method,请求的地址url,是否是异步的isAsync
xhr.open('GET','http://127.0.0.1:5000/api/name',true)
// xhr.setRequestHeader('Content-Type', 'application/json');同时可设置请求头信息,参数对应HTTP请求头的键值对。
  1. 发送请求
// xhr.send()中可设置请求体内容,由于我发送的是GET请求,故不设置参数
xhr.send()
// 当我们调用send()方法时请求被发送到目标地址
  1. 监听响应
    • 在xhr中提供onreadystatechange方法用于监听请求目前的状态,并通过readyState属性获取到目前的状态信息。

      • readyState = 0:表示XHMHttpRequest代理对象已经创建但未初始化(调用open方法)
      • readyState = 1:表示open方法已经被调用,但未发送请求(未调用send方法)
      • readyState = 2:表示请求已经被发送
      • readyState = 3:表示下载中,头部及状态已获得
      • readyState = 4:表示请求过程已经全部完成
    • status属性为HTTP响应状态码

// 每次readyState变化下方法就会被调用
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.response); // response返回响应的正文
    }
};

XHR其他常见实例属性及方法

  • xhr.responseText: 指全部后端的返回数据,在请求没有完成前返回的是从后端接收到的内容。
  • xhr.responseURL:返回响应的序列化 URL,如果 URL 为空则返回空字符串。如果 URL 有锚点,则位于 URL # 后面的内容会被删除。如果 URL 有重定向,responseURL 的值会是经过多次重定向后的最终 URL。
  • xhr.timeout:设置响应的超时时间,单位为毫秒。
  • xhr.upload:返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。
  • xhr.getResponseHeader():传递一个参数返回包含指定响应头文本的字符串。
  • xhr.getAllResponseHeaders():获取所有响应头信息。
  • xhr.abort():当请求发出时,可用该方法终止该请求,当请求被终止时,readyState属性值会被设为0。

Fetch

Fetch是一个现代的 JS API,新的 API 提供了更强大和灵活的功能集。使用的具体是提供了一个全局的fetch()方法,可用于发送请求或者获取资源,它会返回一个会在请求响应后兑现的 promise

用fetch()进行HTTP通信

fetch()在调用时需要传递一个必要的参数:你想要获取的资源的 URL或一个Request对象。但我们只提供URL这个参数时fetch会默认向目标地址发送GET请求。

// 向http://127.0.0.1:5000/api/name发送GET请求
fetch('http://127.0.0.1:5000/api/name').then(res=>{
    console.log(res) // res为响应结果
}).catch(err=>{
    console.log(err)
})

由于fetch是基于Promise,当resolve时会返回一个response对象,可通过then方法获取。从 fetch() 返回的 Promise 不会因 HTTP 的错误状态而被拒绝,即使响应是 HTTP 404500。相反,它将正常兑现(ok 状态会被设置为 false),并且只有在网络故障或者有任何阻止请求完成时,才拒绝。

fetch() 可接收第二个可选参数,为一个配置对象options,可能选项包括但不限于:

  • method:请求的方法,如GET,POST,PUT,DELETE等,默认值为GET
  • headers:请求头信息,可以是 Headers 对象或者带有字符串值的对象字面量。
  • body:请求体信息,信息格式应与headersContent-Type类型一致,有些方法不包含请求体信息如:GET等。
fetch('http://127.0.0.1:5000/api/login',{
    method:'POST',
    headers:{
        "Content-Type":"application/json"
    },
    body:JSON.stringify({
        username:'xump',
        password:'123123'
    })  // 设置JSON格式的请求体
}).then(res=>{
    return res.json()  // res.json() 方法将 Response 对象的响应体解析为 JSON 格式的 JS 对象,返回一个新的 Promise。
}).then(value=>{
    console.log(value)
}).catch(err=>{
    console.log(err)
})