当前位置:   article > 正文

手拉手带你读懂XHR、Ajax,Fetch到底是个啥以及用他们进行网络请求的过程解析

xhr

概述

要对XHR、Ajax,fetch有个深刻的掌握,让我们先来了解一下xhr、ajax、fetch 这三者都是个啥?以及他们的区别和联系。

  1. 首先,什么是XHR,XHR是XMLHttpRequest的缩写,它是是浏览器内置的一种对HTTP请求和响应的处理方式,能够获取和发送数据,支持流处理、进度事件和断点续传,是fetch和Ajax的基础。
  2. 其次,那什么是ajax呢? ajax是Asynchronous JavaScript And XML(异步的JS和XML)的缩写,是一种实现无页面刷新的情况下使用XHR对象向服务器发起请求获取服务器端数据的技术。 它可以使用JSON、XML、html和text文本等格式发送和接收数据
    ajax最吸引人的特性就是它的**“异步”**特性,也就是说可以 在不刷新页面的情况下实现与服务器的通信,交换数据,或更新页面。
  3. 最后,那什么又是Fetch呢?Fetch是基于Promise的新式API,主要用于获取资源,支持流处理和通过拦截器来处理请求和响应,可以在浏览器端和Node.js中使用。

一次完整的ajax请求过程

  1. 创建网络请求的ajax对象(使用XHR)
  2. 监听XHR对象状态的变化,或者监听onload事件(请求完成时触发)
  3. 配置网络请求(通过open方法)
  4. 发送send网络请求
// 1.创建XMLHttpReqest对象
const xhr = new XMLHttpRequest()
// 2.监听对象状态的改变(宏任务)
// 监听四种状态
// xhr.onreadystatechange = function() {
// 	// 1.如果状态不是DONE状态,直接返回
// 	if(xhr.readystate !== XMLHttpRequest.DONE)	return 
// 	// 2.确定拿到了数据
// 	console.log(xhr.response)
// }

// 监听onload事件,是可以确定拿到了数据的
xhr.onload = function() {
  console.log(xhr.response)
}
// 3.配置请求的方式/URL等
xhr.responseType = "json" 
xhr.timeout = 3000
xhr.open("get", "http://xxx.xx.xx", true)
// 4.发送请求
xhr.send()
// 5.获取数据
console.log(xhr.response)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

XHR的state的说明

在这里插入图片描述

http的响应状态码的说明

在这里插入图片描述

客户端传递参数的四种方式

现在我们知道了一次完整的ajax的请求过程是什么样子,但是我们对于客户端发送请求传递的参数方式还不甚了解,接下来就一起来看一下吧

在开发中,我们使用最多的是get和post请求,在发送请求的过程中,我们也可以传递给服务器数据
常见的传递给服务器数据的有以下几种:

  1. get请求的query参数
  2. post请求 x-www-form-urlencoded格式
  3. post请求FormData格式
  4. post请求JSON格式(最常用)
    接下来看一下示例吧
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>客户端传递参数的四种方式</title>
</head>
<body>
  <form class="info">
    <input type="text" name="username">
    <input type="password" name="password">
  </form>
  <button class="send">发送请求</button>
  <script>
  	const formEl = document.querySelector(".info")
    const sendBtn = document.querySelector(".send")
    sendBtn.onclick = function() {
	  // 创建xhr对象
      const xhr = new XMLHttpRequest()

      // 监听数据响应
      xhr.onload = function() {
        console.log(xhr.response)
      }

      // 配置请求
      xhr.responseType = "json"
      
	  // 1.方式1:get请求传递参数
	  xhr.open('get', 'http://xxx.xx.xx/getData?page=1&pageSize=30')
	  xhr.send()
	
	  // 2.方式2:post请求(urlencoded)
	  xhr.open('post', url)
	  const urlParams = "page=1&pageSize=30"
	  xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
	  xhr.send(urlParams)
	
	  // 3.方式3:post请求传递参数(FormData)
	  // 说明:因为post请求的默认content-type就是formdata格式,所以就不用再设置了
	  xhr.open('post', url)
	  // 将formElement对象转成FormData对象
      const formData = new FormData(formEl)
      formData.append("admin", 123456)
      xhr.send(formData)

	  // 4.方式4:post => JSON
	  xhr.open('post', url)
	  const jsonParams = JSON.stringify({page: 1, pageSize: 30})
	  xhr.setRequestHeader('Content-type', 'application/json, charset=utf-8')
	  xhr.send(jsonParams)
	}
  	
  </script>
</body>
</html>
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

ajax网络请求过程的封装

方式1:普通封装

function myAjax({
  url,
  method = "get",
  data = {},
  timeout = 5000,
  headers = {},
  success,
  failure
} = {}) {
  // 1.创建xhr对象
  const xhr = new XMLHttpRequest()
  // 2.监听XHR对象状态的变化
  xhr.onreadystatechange = function() {
    if (xhr.readyState !== XMLHttpRequest.DONE) return
    // 对网络请求返回的状态码进行处理
    if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
      success && success(xhr.response)
    } else {
      failure && failure(xhr.response)
    }
  }

  // 3.设置响应的类型
  xhr.responseType = "json"
  xhr.timeout = timeout

  // 4.1 设置请求参数
  const params = Object.keys(data)
  					.map(key => `${key}=${encodeURIComponent(data[key])}`)
  const paramsString = params.join("&")

  // 4.2 设置header,发送网络请求
  if (method.toLowerCase() === "get") {
    xhr.open(method, url + "?" + paramsString)
    Object.keys(headers).forEach(headerKey => {
    	return xhr.setRequestHeader(headerKey, headers[headerKey])
    })
    xhr.send()
  } else {
    xhr.open(method, url)
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
    Object.keys(headers).forEach(headerKey => {
     	return xhr.setRequestHeader(headerKey, headers[headerKey]) 
    })
    xhr.send(paramsString)
  }

  return xhr
}
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

方式2:基于Promise进行抽取封装

function myAjax({
  url,
  method = "get",
  data = {},
  timeout = 5000,
  headers = {},
  success,
  failure
} = {}) {
  const promise = new Promise((resolve, reject) => {
      // 1.创建xhr对象
    const xhr = new XMLHttpRequest()
    // 2.监听XHR对象状态的变化
    xhr.onreadystatechange = function() {
      if (xhr.readyState !== XMLHttpRequest.DONE) return
      // 对网络请求返回的状态码进行处理
      if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
        resolve(xhr.response)
      } else {
        reject({ status: xhr.status, message: xhr.statusText })
      }
    }

    // 3.设置响应的类型
    xhr.responseType = "json"
    xhr.timeout = timeout

    // 4.1 设置请求参数
    const params = Object.keys(data)
              		 .map(key => `${key}=${encodeURIComponent(data[key])}`)
    const paramsString = params.join("&")

    // 4.2 设置header,发送网络请求
    if (method.toLowerCase() === "get") {
      xhr.open(method, url + "?" + paramsString)
      Object.keys(headers).forEach(headerKey => {
        return xhr.setRequestHeader(headerKey, headers[headerKey])
      })
      xhr.send()
    } else {
      xhr.open(method, url)
      xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
      Object.keys(headers).forEach(headerKey => {
        return xhr.setRequestHeader(headerKey, headers[headerKey]) 
      })
      xhr.send(paramsString)
    }
  }) 
  promise.xhr = xhr
  return promise
}
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

fetch网络请求

fetch可以看做是早期的XHR替代方案,它提供了一种更加现代化的处理方案:
比如:

  • 返回值是一个Promise对象,可以优雅的对返回结果进行处理
  • 不像XHR一样,所有的操作都放在一个对象上

Fetch数据的响应

fetch的数据响应主要分为两个阶段:
阶段一:当服务器返回了响应(response)

  • fetch返回的promise就使用内建的Response class 对象来对响应头进行解析
  • 在这个阶段,可以通过检查响应头,来检查HTTP状态以确定请求是否成功
  • 如果fetch无法建立HTTP请求,例如网络问题,亦或是请求的网址不存在,那么promise就会reject
  • 异常的HTTP状态,例如404或500,不会导致error

可以在response的属性中看到HTTP状态:

  • status:HTTP状态码,例如200
  • ok: 布尔值,如果HTTP状态码为200 - 299,则为true

阶段二:为了获取response body,我们需要使用一个其他的方法调用

  • response.text() – 读取response,并以文本形式返回response
  • response.json() – 将response解析为JSON

fetch网络请求的过程

基于Promise

fetch(url).then(res => {
  console.log(res)
})
  • 1
  • 2
  • 3

基于async、await的方案

async function getData() {
	const res = await fetch(url)
	const data = res.json()
	console.log(data)
}
  • 1
  • 2
  • 3
  • 4
  • 5

基于XHR和fetch进行文件上传

最后,我们来说一下基于XHR和fetch如何进行文件上传,看代码吧

XHR

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>基于XHR进行文件上传</title>
</head>
<body>
  <input class="file" type="file">
  <button class="upload">上传文件</button>
  
  <script>
    const uploadBtn = document.querySelector(".upload")
    uploadBtn.onclick = function() {
      // 1.创建对象
      const xhr = new XMLHttpRequest()

      // 2.监听结果
      xhr.onload = function() {
        console.log(xhr.response)
      }

      xhr.onprogress = function(event) {
        console.log(event)
      }
      
      xhr.responseType = "json"
      xhr.open("post", url)

      // 表单
      const fileEl = document.querySelector(".file")
      const file = fileEl.files[0]

      const formData = new FormData()
      formData.append("avatar", file)

      xhr.send(formData)
    }
  </script>

</body>
</html>
  • 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
  • 42
  • 43

fetch

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>基于fetch进行文件上传</title>
</head>
<body>
  <input class="file" type="file">
  <button class="upload">上传文件</button>
  
  <script>
    const uploadBtn = document.querySelector(".upload")
    uploadBtn.onclick = async function() {
      // 表单
      const fileEl = document.querySelector(".file")
      const file = fileEl.files[0]

      const formData = new FormData()
      formData.append("avatar", file)

      // 发送fetch请求
      const response = await fetch(url, {
        method: "post",
        body: formData
      })
      const res = await response.json()
      console.log("res:", res)
    }

  </script>

</body>
</html>
  • 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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/148367?site
推荐阅读
相关标签
  

闽ICP备14008679号