一文搞懂前端请求XHR,AJAX,Fetch和Axios

在前端开发中,网络请求是必不可少的技能之一。网络请求可以让我们与服务器交换数据,实现各种功能和效果。但是,你知道JavaScript中有哪些网络请求方法吗?你知道它们的区别和优劣吗?你知道如何根据不同的场景选择合适的网络请求方法吗?本文将为你搞懂前端请求的奥秘。

什么是XHR?

XMLHttpRequest (XHR)是一个 JavaScript 对象,它可以用来向服务器发送 HTTP 请求,从而实现网页的局部更新。是 AJAX 编程的核心技术。

XMLHttpRequest包含的一些属性

属性名称 属性作用 备注
onreadystatechange 事件处理器。 当 readyState 属性发生变化时调用
readyState 只读 请求的状态码。 返回 一个无符号短整型(unsigned short)数字(0,1,2,3,4)
response 只读 包含整个响应实体(response entity body)。 返回一个 ArrayBuffer、Blob、Document,或 DOMString,具体是哪种类型取决于 XMLHttpRequest.responseType 的值。
responseText 只读 返回一个 DOMString 该 DOMString 包含对请求的响应,如果请求未成功或尚未发送,则返回 null。
responseType 一个用于定义响应类型的枚举值(enumerated value)。 它包含的值有ArrayBuffer,Blob,Document,json,text
responseURL 只读 返回经过序列化(serialized)的响应 URL 如果该 URL 为空,则返回空字符串。
responseXML 只读 返回一个 Document 其中包含该请求的响应,如果请求未成功、尚未发送或是不能被解析为 XML 或 HTML,则返回 null。
status 只读 请求的响应状态。 status 码是标准的 HTTP status codes
upload 用来表示上传的进度 返回一个 XMLHttpRequestUpload对象
timeout 设置超时时间 xhr.timeout = 2000; // 超时时间,单位是毫秒
withCredentials 用来指定跨域 Access-Control 请求是否应当带有授权信息 如 cookie 或授权 header 头。除非在发送 XMLHttpRequest 请求之前,将 withCredentials 设置为 true,否则来自不同域的 XMLHttpRequest 响应无法为自己的域设置 cookie 值

XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。一个 XHR 代理总是处于下列状态中的一个

状态 描述
0 UNSENT 代理被创建,但尚未调用 open() 方法。
1 OPENED open() 方法已经被调用。
2 HEADERS_RECEIVED send() 方法已经被调用,并且头部和状态已经可获得。
3 LOADING 下载中;responseText 属性已经包含部分数据。
4 DONE 下载操作已完成。

实例方法

var HttpRequest = new XMLHttpRequest()

创建请求

HttpRequest.open(method, url, async, user, password);

method:HTTP 方法,比如 GETPOSTPUTDELETE、等

url:发送请求的 URL

async:可选,布尔参数,默认为true,如果值为 falsesend() 方法直到收到答复前不会返回。

user:可选,用户名用于认证用途;默认为 null。

password :可选,密码用于认证用途,默认为 null。

发送请求

HttpRequest.send(body)

body,可选参数,在 XHR 请求中要发送的数据体

例如:HttpRequest.send(“foo=bar&lorem=ipsum”);

终止请求

 HttpRequest.abort();

终止该请求。当一个请求被终止,它的 readyState 将被置为 XMLHttpRequest.UNSENT (0),并且请求的 status 置为 0。

指定类型

overrideMimeType() 方法必须在 send() 方法之前调用

HttpRequest.overrideMimeType(mimeType)

例如:HttpRequest.overrideMimeType(“text/plain”);

一些常见的 MIME 类型:text/html,text/plain,text/css,text/javascript,application/json,application/xml,image/jpeg,image/png

设置HTTP响应头部的值

setRequestHeader() 方法必须在 open() 方法和 send() 方法之间调用。

HttpRequest.setRequestHeader(header, value);

例如:设置 Content-Type 的值为 application/json

HttpRequest.setRequestHeader(“Content-Type”, “application/json”);

常见的HTTP响应头部

  • Accept:指定客户端能够接收的内容类型。
  • Accept-Charset:指定客户端能够接收的字符集。
  • Accept-Encoding:指定客户端能够接收的内容编码。
  • Accept-Language:指定客户端能够接收的语言。
  • Authorization:包含客户端提供给服务器以验证自己身份的凭证。
  • Cache-Control:指定请求和响应遵循的缓存机制。
  • Connection:指定与连接相关的选项。
  • Content-Length:指定请求体的长度,以字节为单位。
  • Content-Type:指定请求体的 MIME 类型。
  • Cookie:包含来自客户端的 Cookie 值。
  • Host:指定被请求资源的主机名和端口号。
  • If-Modified-Since:允许在请求中包含条件,只有请求内容在指定日期后或之后修改过才返回它。
  • Referer:包含当前页面的 URL,用于标识请求是从哪个页面发送过来的。
  • User-Agent:包含发起请求的用户代理。

获取响应头

获取指定响应头文本的字符串

var myHeader = HttpRequest.getResponseHeader(name);


//name一个字符串,表示要返回的报文项名称。
//例如:
var contentType=HttpRequest.getResponseHeader("Content-Type")); 

获取所有响应头

var headers = HttpRequest.getAllResponseHeaders();

返回结果:每一行通过\r\n 来进行分割。

date: Fri, 08 Dec 2023 21:04:30 GMT\r\n
content-encoding: gzip\r\n
x-content-type-options: nosniff\r\n
server: meinheld/0.6.1\r\n
x-frame-options: DENY\r\n
content-type: text/html; charset=utf-8\r\n
connection: keep-alive\r\n
strict-transport-security: max-age=63072000\r\n
vary: Cookie, Accept-Encoding\r\n
content-length: 6502\r\n
x-xss-protection: 1; mode=block\r\n

其他

返回所有的响应头

var headers = HttpRequest.getAllResponseHeaders();

事件

说明

loadstart:用于指示请求已经开始加载数据,可以使用 loadstart 事件来检测请求何时开始加载数据。

load:当一个XMLHttpRequest请求完成的时候会触发load 事件。

loadend:在一个资源的加载进度停止之后被触发 (例如,在已经触发“error”,“abort”或“load”事件之后)

progress:progress 事件用于返回进度信息,在请求接收到更多数据时定期触发。

error:当请求遇到错误时,将触发error 事件。

abort:当一个请求终止时 abort 事件被触发,比如程序执行 XMLHttpRequest.abort()。

示例

<div class="controls">
    <input class="xhr success" type="button" name="xhr" value="Click to start XHR (success)" />
    <input class="xhr error" type="button" name="xhr" value="Click to start XHR (error)" />
    <input class="xhr abort" type="button" name="xhr" value="Click to start XHR (abort)" />
</div>


<textarea readonly class="event-log"></textarea>

const xhrButtonSuccess = document.querySelector('.xhr.success');
const xhrButtonError = document.querySelector('.xhr.error');
const xhrButtonAbort = document.querySelector('.xhr.abort');
const log = document.querySelector('.event-log');




function handleEvent(e) {
    log.textContent = log.textContent + `${e.type}: ${e.loaded} bytes transferred\n`;
}




function addListeners(xhr) {
    xhr.addEventListener('loadstart', handleEvent);
    xhr.addEventListener('load', handleEvent);
    xhr.addEventListener('loadend', handleEvent);
    xhr.addEventListener('progress', handleEvent);
    xhr.addEventListener('error', handleEvent);
    xhr.addEventListener('abort', handleEvent);
}

function runXHR(url) {
    log.textContent = '';

    const xhr = new XMLHttpRequest();
    addListeners(xhr);
    xhr.open("GET", url);
    xhr.send();
    return xhr;
}

xhrButtonSuccess.addEventListener('click', () => {
    runXHR('dgszyjnxcaipwzy.jpg');
});

xhrButtonError.addEventListener('click', () => {
    runXHR('https://somewhere.org/i-dont-exist');
});

xhrButtonAbort.addEventListener('click', () => {
    runXHR('dgszyjnxcaipwzy.jpg').abort();
});

什么是AJAX?

AJAX 代表异步的 JavaScript 和 XML(Asynchronous JavaScript And XML)。简单点说,就是使用 XMLHttpRequest(XHR)对象与服务器通信。

Ajax 本身不是一种编程语言,而是一种利用以下技术的组合。

  • 浏览器内置的XMLHttpRequest对象(向服务器请求数据)
  • JavaScript和HTML DOM(显示或使用数据)
  • XML、JSON或纯文本(作为数据传输格式)

Ajax 中的 X 代表 XML,但是 JSON 才是首选,因为它更加轻量

AJAX的工作原理

image.png

  • 在网页中发生一个事件(页面加载,按钮被点击等)
  • JavaScript创建一个XMLHttpRequest对象
  • XMLHttpRequest对象向服务器发送一个请求
  • 服务器处理请求
  • 服务器向网页返回一个响应
  • JavaScript读取响应
  • JavaScript执行相应的操作(如更新网页)

AJAX示例

创建一个XMLHttpRequest对象,用来向服务器发送http请求

const httpRequest = new XMLHttpRequest();

定义一个回调函数,当请求状态发生变化时触发

httpRequest.onreadystatechange = function() {
  //判断请求是否完成(readyState为4)并且成功(status为200)
  if (httpRequest.readyState === 4 && httpRequest.status === 200) {
    //在这里处理返回的数据,比如显示在网页上
    console.log(httpRequest.responseText);
  }
};

建立一个GET请求,指定请求的URL

httpRequest.open("GET", "https://example.com/api/data");

发送请求

httpRequest.send();

Ajax的优缺点

优点:

  1. 减少页面刷新:Ajax 可以在页面不刷新的情况下获取和显示数据,减少了用户等待时间和流量消耗。
  2. 提高用户体验:由于 Ajax 可以实现异步请求和响应,使得用户可以在不中断操作的情况下获取数据,从而提高了用户的体验。
  3. 减轻服务器压力:由于 Ajax 可以部分更新页面,减少了服务器处理请求的次数,从而减轻了服务器的压力。
  4. 支持多种数据格式:Ajax 可以支持多种数据格式,如 XMLJSON 等,使得数据的传输和处理更加灵活。

缺点:

  1. SEO 不友好:由于 Ajax 的异步请求不会刷新整个页面,搜索引擎很难获取 Ajax 加载的数据,从而降低了网站的 SEO 优化效果。
  2. 安全性问题:Ajax 可能会导致跨站点脚本攻击(Cross-site scripting, XSS)跨站点请求伪造(Cross-site request forgery, CSRF)等安全问题,开发人员需要采取相应的安全措施。

什么是Fetch?

Fetch 是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。

Fetch的用法

基本语法

let promise = fetch(url, [options])
  • url —— 要访问的 URL。
  • options —— 可选参数:method,header 等。
//典型的 fetch 请求由两个 await 调用组成
let response = await fetch(url, options); // 解析 response header
let result = await response.json(); // 将 body 读取为 json

//或者以promise的形式
fetch(url, options)
  .then(response => response.json())
  .then(result => /* process result */)

Headers

Headers对象表示HTTP请求或响应的头部信息。我们可以使用Headers对象来设置请求或响应的头部信息,比如Content-Type、Authorization等。

const headers = new Headers({
  'Content-Type': 'application/json',
  'Authorization': 'Bearer token'
});




fetch('https://api.example.com/data', {
  headers: headers
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

它包含的一些实例方法

Headers.append():给现有的 header 添加一个值,或者添加一个未存在的 header 并赋值。

const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Bearer my-token');

Headers.delete():从 Headers 对象中删除指定 header.

Headers.entries():以 迭代器 的形式返回 Headers 对象中所有的键值对。


var myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.append('Vary', 'Accept-Language');




for (var pair of myHeaders.entries()) {
   console.log(pair[0]+ ': '+ pair[1]);
}




//输出结果
content-type: text/xml
VM186:6 vary: Accept-Language

Headers.get():以 ByteString 的形式从 Headers 对象中返回指定 header 的全部值。

console.log(headers.get('content-type')); // 输出: "application/json"

Headers.has():以布尔值的形式从 Headers 对象中返回是否存在指定的 header.

Headers.keys():以迭代器的形式返回 Headers 对象中所有存在的 header 名。

Headers.set():替换现有的 header 的值,或者添加一个未存在的 header 并赋值。

Headers.values():以迭代器的形式返回 Headers 对象中所有存在的 header 的值。

Request

Request对象表示一个HTTP请求。我们可以使用Request对象来设置请求选项,比如请求URL、请求方法、请求头等。下面是Request对象的使用示例:

const request = new Request('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ name: 'John', age: 30 })
});



fetch(request)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

它的部分属性

属性 说明
Request.method 包含请求的方法 (GET, POST, 等.)
Request.url 包含这个请求的 URL。
Request.headers 包含请求相关的Headers对象。
Request.context 包含请求的上下文 (例如:audio, image, iframe, 等)
Body.body body 类型可以是一个Blob,BufferSource, FormData, URLSearchParams, USVString 或者ReadableStream类型

Response

fetch()请求成功以后,得到的是一个 Response 对象。它对应服务器的 HTTP 回应。我们可以使用Response对象来获取响应的信息,比如状态码、响应头、响应体等

fetch('https://api.example.com/data')
  .then(response => {

    console.log(response.status);
    console.log(response.headers.get('Content-Type'));
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error(error));

image-20230609100514249

可以看到返回的有这些信息

属性 说明
Response.ok 返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
Response.status 返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)。
Response.statusText 返回一个字符串,表示 HTTP 回应的状态信息(例如请求成功以后,服务器返回”OK”)。
Response.url 返回请求的 URL。如果 URL 存在跳转,该属性返回的是最终 URL。
Response.type 包含一种响应的类型,它的值有basic,cors,error,opaque,opaqueredirect。
Response.redirected 返回一个布尔值,表示请求是否发生过跳转。

Response.type

  • basic:普通请求,即同源请求。
  • cors:跨域请求。
  • error:网络错误,主要用于 Service Worker。
  • opaque:如果fetch()请求的type属性设为no-cors,就会返回这个值,详见请求部分。表示发出的是简单的跨域请求,类似<form>表单的那种跨域请求。
  • opaqueredirect:如果fetch()请求的redirect属性设为manual,就会返回这个值,详见请求部分。

使用示例

发送请求

//GET请求
fetch('https://api.example.com/data')
  .then(response => console.log(response))
  .catch(error => console.error(error));






//POST请求
const requestOptions = {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ username: 'axjy', password: '123456' })
};

fetch('https://api.example.com/login', requestOptions)
  .then(response => console.log(response))
  .catch(error => console.error(error));

处理响应数据

处理响应数据,可以使用 Response对象 提供的方法。

fetch('https://example.com/data.json')

  .then(response => response.json())//使用`.json()`方法将响应正文解析为 `JSON格式` 的数据
  .then(data => console.log(data))
  .catch(error => console.error(error)); //处理错误,如果请求失败,catch() 方法将被调用

处理HTTP错误

如果服务器返回HTTP错误状态代码(例如404或500),fetch() 方法不会引发错误。它会将响应对象传递给 then() 方法。所以可以使用 Response 对象的属性来确定响应的状态代码,并相应地处理响应。

fetch('https://example.com/data.json')

  .then(response => {

    //可以根据response.ok,response.status来错误http错误的状态码
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error(error));

Fetch的优缺点

优点

  • 支持跨域请求:在配置中,添加mode: ‘no-cors’就可以跨域了
fetch('/users.json', {
    method: 'post', 
    mode: 'no-cors',
    data: {}
}).then(function() { /* handle response */ });
  • 可以自定义请求头,更好地控制请求。

缺点

  • fetch只对网络请求报错,对400500都当做成功的请求,需要封装去处理

  • fetch没有办法原生监测请求的进度,而XHR可以。

基于 fetch 封装的库

redaxios,轻量级的 Axios 替代品,可以在浏览器和Node.js环境中使用。适合那些想要使用 Axios API 但又不想引入额外依赖的场景。

umi-request,是一个轻量级的 http 请求库,它兼具 fetch 和 axios 的特点,适合在 umi 框架中使用

什么是Axios?

Axios是一个基于promise网络请求库,在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

Axios的使用

基本使用

Axios文档已经写的很清楚了

取消请求

v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController 取消请求:

const controller = new AbortController();


axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// 取消请求
controller.abort()

请求体编码

默认情况下,axios将 JavaScript 对象序列化为 JSON 。 要以application/x-www-form-urlencoded格式发送数据,可以使用qs 库编码数据。

const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));

Axios 优缺点

优点:

  1. Promise API:Axios使用Promise API,因此可以轻松处理异步操作。Promise API具有更清晰的语法和更好的可读性,因为它们允许在异步操作完成之前进行链式调用,从而避免了回调地狱问题。
  2. 简单易用:Axios的API设计简单且易于使用,而且它还提供了许多可用的配置选项,例如设置请求头、超时时间、认证等等,让开发者可以更轻松地定制请求。
  3. 可扩展性:Axios可以通过添加拦截器(interceptors)来实现许多自定义功能,例如添加请求拦截器、响应拦截器和错误拦截器等等。这些拦截器可以让开发者在请求和响应过程中进行自定义操作。

缺点:

  1. 可能出现跨域问题:Axios不能直接解决跨域请求的问题。尽管Axios可以设置跨域请求头,但是它不能绕过浏览器的安全限制。这意味着在某些情况下,开发者可能需要通过其他方式来解决跨域请求的问题。

总结

XHR:是一个 JavaScript 对象

ajax:是一个技术统称,XMLHttpRequest 是实现 Ajax 的一种方式。

fetch:是一个API,es6新增的用于网络请求标准api。

axios:是一个库,用于网络请求的第三方库。

参考资料:

Ajax – Web 开发者指南 | MDN (mozilla.org)

AJAX Introduction

What is AJAX?

geeksforgeeks

Fetch API


?【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

? JavaScript的Proxy代理怎么用?

? JS中的getter和setter你会用吗?

? 深入理解ES6箭头对象

? JS的装饰器模式实例分析

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYExrRd4' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片