likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 38

在前端开发中,网络请求是必不可少的技能之一。网络请求可以让我们与服务器交换数据,实现各种功能和效果。但是,你知道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 代理总是处于下列状态中的一个

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

实例方法

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的工作原理

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

  • 在网页中发生一个事件(页面加载,按钮被点击等)
  • 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.bodybody 类型可以是一个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));

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

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

属性说明
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的装饰器模式实例分析

转载自:https://juejin.cn/post/7243276385895497787
评论
请登录