4.3 响应处理
4.3.1 Axios
在 Axios 中,响应数据默认以 JSON 格式提供。我们所要做的就是访问响应对象的数据属性:
axios.get('https://fakestoreapi.com/products/1') .then(response => { console.log(response.data); }, error => { console.log(error); });
可以使用配置选项更改响应类型,即responseType属性。它指示服务器将响应的数据类型,选项包括:
arraybuffer
document
json (default)
text
stream
blob
4.3.2 Fetch
使用 Fetch,在访问响应数据之前我们还需要执行一个步骤:
fetch('https://fakestoreapi.com/products/1') .then((response) => response.json()) .then((data) => { console.log(data); }) .catch((error) => console.error(error));
使用fetch()
时,我们会在所有标头到达后立即收到响应。 那时,我们还没有尚未加载的 HTTP 响应主体。 这就是我们收到另一个应许的原因。简而言之,response.json()
等待正文加载。
我们每天使用的 JSON 对象通常都比较小。但是,想象一下您必须加载非常大的图像的情况。这可能需要一段时间,在图像完全加载之前我们可能需要相关信息。
要阅读有关
response.json()
的更多信息,请查看此链接。
4.3.2 总结
Fetch 是一个相对低级的 API,可以精确控制加载过程。 它伴随着每次使用它时必须处理两个 Promise
的成本。
Fetch
要求我们在处理响应时多做一步,因为它返回一个Promise
,此时我们没有我们需要的JSON
数据格式,因此需要.json()
方法。- 要在
Axios
中访问响应数据,我们使用data
属性,而在使用fetch()
时,最终数据可以命名为任何变量。
4.4 错误处理
还记得 Axios
和 Fetch
都是基于 promise
的 HTTP
客户端吗?因此,他们都返回一个可以 resolve
或 reject
的 Promise
。然而,就相似性而言,仅此而已—— promise
得到 resolve
或 reject
的条款大不相同。
4.4.1 Axios
让我们看一个典型的 Axios
错误处理示例,使用 .catch()
:
axios.get('https://codilime.com/') .then(response => console.log(response.data)) .catch((err) => console.log(err.message));
每个响应都包含一个状态属性,它只是一个 HTTP 响应状态代码。这些代码表示请求是否已成功完成。例子包括:
- 200
OK
- 请求成功, - 403
Forbidden
——客户端无权访问内容, - 418
I'm a teapot
- 服务器拒绝尝试用茶壶冲泡咖啡(不,这不是玩笑,请在此处查看)。
可以在此处阅读有关这些 HTTP 响应状态代码的更多信息。
现在我们知道了 HTTP 响应状态代码是什么,我们可以理解 Axios 错误处理是如何工作的。Axios
将拒绝任何状态码超出 200-299 范围(成功响应)的Promise
。
我们可以检查错误对象以获取有关错误的更多信息:
axios.get('https://fakestoreapi.com/products/1') .then(response => console.log(response.data)) .catch((err) => { if (err.response) { // The request was made, but the server responded with a status code that falls out of the 2xx range const { status } = err.response; if (status === 401) { // The client must authenticate itself to get the requested response } else if (status === 502) { // The server got an invalid response } ... } else if (err.request) { // The request was made, but no response was received } else { // Some other error } });
当我们在错误对象上有 response
属性时,这意味着发出了请求,并且服务器响应了,但是响应状态代码在2xx 范围之外。另一方面,请求属性表示已发出请求,但未收到响应。如果这两者都不正确,则表示设置网络请求时出现问题,从而触发错误。
4.4.2 Fetch
获取错误处理与 Axios 有很大不同。最重要的区别是,如果我们收到 HTTP 错误,它不会reject Promise
——不成功的响应仍然会得到解决。因此,HTTP 错误在 .then
块中处理。只有在网络出现故障的情况下,Fetch API Promise
才会被拒绝。
fetch('https://fakestoreapi.com/products/1') .then(response => { if (!response.ok) { throw Error(`HTTP error: ${response.status}`); } return response.json(); }) .then(data => console.log(data)) .catch((error) => { console.log(error) });
使用 Fetch API 需要我们检查response.ok属性来控制 HTTP 错误。
两个最重要的响应属性是status和ok:
- status - 响应状态代码(整数)。
- ok - 检查状态是否在 2xx(布尔值)范围内的简写。
在成功的场景中,它们将分别具有200和true值:
{ ... status: 200, ok: true, ... }
但是,在错误情况下,我们将获得 HTTP 错误状态代码和false。例如,如果我们没有通过身份验证来接收请求的响应,我们将得到:
{ ... status: 401, ok: false, ... }
4.4.3 总结
在 Axios 中,超出 200-299 范围(成功响应)的响应将被自动拒绝。使用 .catch() 块,我们可以获得有关错误的信息,例如是否收到响应,如果收到,则返回其状态代码。
另一方面,在 fetch() 中,不成功的响应仍然得到解决。这就是为什么我们必须检查响应的ok属性并在它设置为 false 时抛出错误。然后在.catch() 块中处理该错误。
4.5 响应超时
在设定的时间后中止请求的功能是发出 HTTP 请求的重要部分。如果没有该功能,请求可能会挂起并可能导致我们的应用程序变慢。
4.5.1 Axios
使用 Axios 设置响应超时非常容易。我们所要做的就是在请求的配置对象中添加一行:
axios.get(url, { ... timeout: 2000, ... }) .then(response => console.log(response.data)) .catch(err => console.log(err.message))
超时是一个可选参数,以毫秒为单位。如果超过两秒,上述请求将被中止,并记录错误。timeout属性的默认值为0,表示没有超时。
4.5.2 Fetch
用 Fetch API 做同样的事情并不容易。要实现相同的行为,我们可以使用名为AbortController的接口和fetch() 方法配置选项:
const controller = new AbortController(); const options = { method: 'POST', signal: controller.signal, body: JSON.stringify({ firstName: 'David', lastName: 'Pollock' }) }; const promise = fetch('/login', options); const timeoutId = setTimeout(() => controller.abort(), 4000); promise .then(response => {/* handle the response */}) .catch(error => console.error('timeout exceeded'));
在这里,通过创建一个AbortController对象,我们可以访问abort() 方法和信号对象,它允许我们稍后中止该请求。信号是 AbortController
的一个只读属性,提供了一个与请求沟通或中止请求的方法。如果服务器在四秒内没有回应,controller.abort()
就会被调用,操作就会终止。
请注意,如果您在fetch() 完成后调用*abort() ,它只会忽略它。
4.5.3 总结
fetch() 没有像 Axios 那样为我们提供超时配置选项。相反,我们必须使用AbortController接口和setTimeout函数。Axios 隐藏了很多这样的样板文件,这使其成为大多数用例的明显赢家。 但是,我们已经知道 Fetch 是一个低级 API。根据您的需要,在响应超时和取消请求方面,您可能仍然更喜欢 Fetch 而不是 Axios。
4.6 HTTP 请求和响应拦截
Axios
的主要功能之一是其拦截 HTTP请求
的能力。当你需要检查或改变从你的应用程序到服务器的HTTP请求或反之亦然时,HTTP拦截器就会派上用场(例如,记录、认证或重试一个失败的HTTP请求)。
有了拦截器,你就不必为每个HTTP请求单独编写代码。当你想为你处理请求和响应的方式设置一个全局策略时,HTTP拦截器很有帮助。
想象一个场景,我们必须保存从我们的应用程序发送的每个 HTTP 请求的日志。向每个请求添加这样的代码很麻烦,容易出错,简而言之,不可行。这就是拦截器发挥作用的时候。它们允许我们消除为每个请求重复代码,而是创建和设置处理请求和响应的全局行为。
简而言之,HTTP 拦截器用于在客户端和服务器端 HTTP 请求和响应之间应用自定义逻辑。它们可用于不同的操作,例如:
- 修改 HTTP 标头或正文
- 设置自定义令牌
- 修改响应
4.6.1 Axios
Axios 具有用于简单创建 HTTP 拦截器的功能 - 包括响应和请求拦截器。首先,让我们看一个请求拦截器:
axios.interceptor.request.use(config => { // log data before HTTP request is sent console.log('HTTP request being sent...'); return config; })
上面的代码会在发送任何 HTTP 请求之前产生一条日志消息。类似地,响应拦截器被定义为在它们被then或catch处理之前运行一些代码:
axios.interceptor.response.use( function (response) { // This function will be triggered on any status code inside 2xx range return response; }, function (error) { // This function will be triggered on any status code outside of 2xx range return Promise.reject(error); } )
例如,当您想要设置一个策略以在失败的情况下始终重试一次 HTTP 请求时,响应拦截器可能会派上用场。
如果您愿意,Axios 还允许您删除拦截器:
const requestInterceptor = axios.interceptor.request.use(config => { // log data before HTTP request is sent console.log('HTTP request being sent...'); return config; }); axios.interceptor.request.eject(requestInterceptor);
4.6.2 Fetch
使用 Fetch API 时,我们没有配置选项或特殊的内置函数来实现拦截器。然而,Vanilla JS(一种快速、轻量级、跨平台的框架)就足够了:
fetch = (originalFetch => { return (...arguments) => { const result = originalFetch.apply(this, arguments); return result.then(console.log('HTTP request being sent ...')); }; })(fetch);
上面的代码是一个 HTTP 请求拦截器的实现。我们可以像使用普通的旧fetch() 函数一样使用它:
fetch('https://fakestoreapi.com/products/1') .then(response => response.json()) .then(console.log)
4.6.3 总结
Axios 为我们提供了开箱即用的功能来创建 HTTP 请求和响应拦截器。 与响应超时类似,它隐藏了大部分样板文件并为我们提供了一个漂亮、易于使用的界面。
另一方面,我们有 Fetch API,同样因为它的级别低,没有为我们提供这样的方法。基于 fetch() 的 HTTP 拦截器很容易编写,并且可以在 Internet 上找到。
再一次,我们可以选择避免样板文件而不是更细粒度的控制和自定义选项。选择应基于用例和个人需求。
4.7 download 进度
在 XMLHttpRequests 仍然被广泛使用的日子里,它是用于实现进度指示器的.onprogress 方法。今天,这些指标仍然是加载资产的重要组成部分,尤其是大资产,尤其是对于互联网连接速度较慢的用户。但是,我们不必再摆弄这个接口了。
让我们下载一张图片!
4.7.1 Axios
在使用axios库的时候,一般会使用axios Progress Bar来实现一个进度条。
它可以通过 NPM 包获得:
npm install --save axios-progress-bar
或者通过 CDN:
<script src="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/index.js"></script>
之后,我们需要将 CSS 导入到 HTML 中,或者通过带有模块打包器的 JavaScript,例如webpack:
<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/nprogress.css" />
就是这样的设置。现在我们可以实现进度条了。我们必须(仅一次)调用loadProgressBar()
函数,该函数可选择采用两个参数 - config 和 instance
。配置对象的属性可以在这里看到。第二个参数用于传递自定义 axios 实例。现在,我们将跳过这两个参数以使其尽可能简单。
... <img id="codilime-logo" /> ... <script type="text/javascript"> loadProgressBar(); const url = 'http://codilime.com/image/path/logo.jpg'; function downloadFile(url) { axios.get(url, { responseType: 'blob', }) .then(response => { const fileReader = new window.FileReader(); fileReader.readAsDataURL(response.data); fileReader.onload = () => { document.getElementById('codilime-logo').setAttribute('src', fileReader.result); }; }) .catch(error => { console.log(error) }) } downloadFile(url); </script>
上面的代码使用了FileReader API。它允许我们使用File或Blob对象读取文件的内容。FileReader.readAsDataURL()
开始读取指定blob的内容,完成后,FileReader.result
属性包含一个编码字符串。我们还使用了load事件,它会在读取成功完成时触发。那是我们将结果插入元素中的src属性的时候。
Axios 进度条设计基于angular-loading-bar。它使用负责在浏览器中显示加载栏的nprogress模块。
4.7.2 Fetch
使用 Fetch API 实现进度条并不容易,我们没有像 Axios 那样为我们提供简单易用 API 的包。不过不要害怕 - 正如你可能猜到的那样,还有另一个低级 API 允许我们实现进度条。可悲的是,有更多的代码。
我们将使用ReadableStream API。这个接口代表一个可读的字节数据流。此外,ReadableStream实例存在于Response 对象的body属性中。我们将使用该字节流来跟踪进度。
HTML 文件:
... <div id="progress-bar" src="">Progress bar</div> <img id="codilime-logo" /> ...
文件:
const el = document.getElementById('progress-bar'); fetch('http://codilime.com/image/path/logo.jpg') .then(response => { if (!response.ok) { throw Error(`HTTP error: ${response.status}`); } // Ensure ReadableStream is supported if (!response.body) { throw Error('ReadableStream API is not supported in this browser'); } // The Content-Length header indicates the size of the message body, in bytes const contentLength = response.headers.get('content-length'); if (!contentLength) { throw Error ('Content-Length response header unavailable'); } const total = parseInt(contentLength, 10); let loaded = 0; return new Response( new ReadableStream({ start(controller) { const reader = response.body.getReader(); read(); // read() function handles each data chunk function read() { reader.read().then(({ done, value }) => { // No more data to read if (done) { controller.close(); return; } loaded += value.byteLength; progress({ loaded, total }); // Get the data and send it to the browser via the controller controller.enqueue(value); read(); }).catch(error => { console.error(error); controller.error(error); }) } } }) ); }) .then(response => response.blob()) .then(data => { document.getElementById('codilime-logo').src = URL.createObjectURL(data); }) .catch(error => { console.error(error); }) function progress({ loaded, total }) { el.innerHTML = Math.round(loaded / total * 100) + '%'; }
好的,这是很多代码 - 让我们一步一步地完成它。
<div id="progress-bar" src="">Progress bar</div> <img id="codilime-logo" />
在 HTML 文件中,我们创建一个img标签,与 Axios 示例中的相同。此外,我们必须创建一个div作为我们的进度条,我们不使用外部包,所以我们必须自己创建它。
const el = document.getElementById('progress-bar'); fetch('http://codilime.com/image/path/logo.jpg') .then(response => { if (!response.ok) { throw Error(`HTTP error: ${response.status}`); } // Ensure ReadableStream is supported if (!response.body) { throw Error('ReadableStream API is not supported in this browser'); } // The Content-Length header indicates the size of the message body, in bytes const contentLength = response.headers.get('content-length'); if (!contentLength) { throw Error ('Content-Length response header unavailable'); } ...
然后进入 JS。我们将div元素保存在 el变量中。之后,我们提出请求。标准程序是检查是否存在任何 HTTP 错误、是否支持 ReadableStream API
,以及是否存在 Content-Length
标头。
所有主流浏览器都支持 ReadableStream API
,您可以通过caniuse检查。因此,您可以在实现中省略第二个 if 语句。
我们添加第三个 if 语句,因为要访问标头,服务器必须发送 CORS 标头 - Access-Control-Expose-Headers - “Access-Control-Expose-Headers: content-length”
。此响应标头允许服务器指示哪些响应标头应提供给浏览器中运行的脚本,以响应跨域请求。
现在,进入返回的响应。
... const total = parseInt(contentLength, 10); let loaded = 0; return new Response( new ReadableStream({ start(controller) { ...
ReadableStream
构造函数从给定的处理程序创建并返回一个可读流对象。它接受underlayingSourceobject
,其中包含定义构造流实例行为方式的方法和属性。您可以在此处阅读更多信息。
在我们的例子中,我们唯一需要的是start(controller)
方法。构造对象时立即调用它。它的内容应该旨在访问流源和设置流功能。控制器属性是ReadableStreamDefaultController或ReadableByteStreamController,具体取决于类型属性。
... const reader = response.body.getReader(); ...
ReadableStream
的getReader()方法创建一个读取器并将流锁定到它。在该锁定期间,在释放此读取器之前,无法获取其他读取器。
... read(); // read() function handles each data chunk function read() { reader.read().then(({ done, value }) => { // No more data to read if (done) { controller.close(); return; } loaded += value.byteLength; progress({ loaded, total }); // Get the data and send it to the browser via the controller controller.enqueue(value); read(); }).catch(error => { console.error(error); controller.error(error); }) } ...
在 read()
函数中,我们调用 reader
的 read()
方法,它返回一个Promise
,提供对流内部队列中下一个块的访问。 如果块可用,Promise
将通过以下形式的对象实现:
{ value: theChunk, done: false, }
否则,如果流关闭,Promise
将通过以下形式的对象实现:
{ value: undefined, done: true, }
只有当流显示错误时,promise 才会被 reject
。
... // No more data to read if (done) { controller.close(); return; } loaded += value.byteLength; progress({ loaded, total }); // Get the data and send it to the browser via the controller controller.enqueue(value); read(); ...
如果没有更多数据要读取,我们使用close()
方法关闭关联的流。否则,我们使用进度函数修改div
元素。之后,我们使用enqueue()
函数将给定块排入关联流中。
... console.error(error); controller.error(error); ...
在 .catch
子句中,我们使用 error()
方法,这会导致未来与关联流的任何交互出错。
请记住,这只是使用 Fetch API 实现进度条的一种方式。您可以在此GitHub 存储库中查看此实现和其他实现。
4.7.3 总结
这是和以前一样的故事。我们有一个选择。对于高级 Axios API
,我们必须使用一个额外的包—— Axios Progress Bar
。
另一方面,我们有低级的 Fetch API
,我们也可以在其中实现进度条。更重要的是,我们可以用各种不同的方式来实现它。这肯定是更多的代码,而且,像往常一样,它提供了对数据处理每个阶段发生的事情的更细粒度的控制。最重要的是,我们不需要任何额外的包。这一切都可以只用 JavaScript 和一些 API 来完成。
4.8 并行请求
如果您已经完成了进度条部分,您会很高兴听到 Axios
和 Fetch API
都提供了易于使用的方式来同时发出多个请求。让我们看看它的实际效果。
4.8.1 Axios
在 Axios 中,我们创建了一个请求数组。每个请求的创建方式与以前相同。此外,我们使用axios.all
方法发出多个 HTTP 请求:
const endpoints = [ 'https://fakestoreapi.com/products/1', 'https://fakestoreapi.com/products/2', 'https://fakestoreapi.com/products/3' ]; axios.all( endpoints.map(endpoint => axios.get(endpoint)) ).then(console.log)
我们通过每个端点进行映射,向当前端点发出HTTP GET请求
。
axios.all
返回一个数组作为响应,其中每个条目对应于我们的端点数组中的一个端点。因此,我们将在data[0]
处获得endpoint
codilime.com/endpoint1
的响应,在data[1]
处获得 codilime.com/endpoint2
等的响应。
值得庆幸的是,Axios 还提供了axios.spread方法,它的行为类似于常规的 JavaScript 展开运算符 - ... :
const endpoints = [ 'https://fakestoreapi.com/products/1', 'https://fakestoreapi.com/products/2', 'https://fakestoreapi.com/products/3' ]; axios.all( endpoints.map(endpoint => axios.get(endpoint)) ) .then(axios.spread((res1, res2, res3) => { console.log(res1.data, res2.data, res3.data); }))
4.8.2 Fetch
使用 Fetch API 时,我们可以使用 Promise.all()
方法和解构实现类似的行为:
js
复制代码
const endpoints = [ 'http://codilime.com/endpoint1', 'http://codilime.com/endpoint2', 'http://codilime.com/endpoint3', ]; Promise.all( endpoints.map(endpoint => fetch(endpoint)) ) .then(async ([ res1, res2, res3 ]) => { const res1JSON = await res1.json(); const res2JSON = await res2.json(); const res3JSON = await res3.json(); console.log(res1JSON, res2JSON, res3JSON); }))
如果您不熟悉Promise.all()
,它会接受可迭代的Promise
(例如数组)并返回单个Promise
,该Promise
解析为输入Promise
结果的数组。
4.8.3 总结
在同时发出多个请求时,我们有两个非常相似的解决方案。一种利用外部库方法,另一种使用内置 JavaScript 方法。但是,这两个实现的含义和流程几乎相同。
5、总结
- 底层实现:
Ajax
的底层实现使用了浏览器内置的XMLHttpRequest(XHR)
对象,使用方式相对繁琐;而Fetch API
则使用了基于Promise
的fetch()
函数。Axios
则是基于XHR
和node.js
的http
封装的库。 - 兼容性:
Ajax
具有较好的兼容性,几乎可以在所有浏览器上运行。Fetch
和Axios
虽然也具有较好的兼容性,但需要考虑到浏览器版本和功能支持问题,需要使用polyfill
或其他兼容性解决方案来保证兼容性。 Promise
和回调函数:Ajax
不支持Promise
,通常使用回调函数来处理异步请求的结果,这种方式容易出现回调地狱的情况;Fetch
和Axios
则使用Promise
对象来处理异步请求的结果,可以更加方便地进行链式调用和错误处理。- 浏览器支持:
Ajax
和XHR
对象在旧版浏览器中的支持存在一些问题;Fetch API
是比较新的标准,可能会存在一些兼容性问题;Axios
则是一个基于Promise
的库,支持各种现代浏览器和Node.js
环境。 - 功能和扩展性:
Ajax
和XHR
对象提供了基本的请求和响应功能,但是缺乏灵活性和扩展性。Fetch API
则提供了更加丰富的请求和响应选项,支持请求和响应的拦截、转换、缓存等功能。Axios
则在Fetch API
的基础上提供了更加强大和灵活的功能,如请求和响应的取消、并发、批量处理等。 - 请求和响应拦截器:
Axios
支持请求和响应拦截器,可以在请求或响应被处理前或后进行操作,比如添加请求头、修改响应数据等。这对于需要对请求或响应进行全局处理的场景非常有用。Fetch
和Ajax
相比较没有内置的请求和响应拦截器,需要手动编写实现。 - 库的大小和性能:
Ajax
和XHR
对象是浏览器内置的API
,不需要引入额外的库,因此体积较小,但是在处理大量请求时性能可能较差。Fetch API
是新的标准,需要使用polyfill
或者引入额外的库,因此体积较大,但是性能相对较好。Axios
是一个功能丰富的库,体积相对较大,但是性能表现较好,尤其在处理大量请求时优势更为明显。 - 并发请求:
Axios
可以方便地发送多个并发请求,通过Promise.all
或Promise.race
来处理响应。而Fetch
和Ajax
只能通过Promise
来处理单个请求,需要手动编写实现并发请求的逻辑。 - 对于同源策略的处理:
Ajax
和Fetch API
都遵循浏览器的同源策略,不能直接请求不同域名的资源。但是,它们可以通过设置CORS
或使用JSONP
等技术来实现跨域请求。而Axios
对跨域请求的处理更为简单,可以通过使用代理等方式来实现跨域请求。 - 请求的取消和超时:
Axios
支持请求的取消和超时设置,可以在发送请求时设置cancelToken
和timeout
选项,对于需要及时取消或超时的请求非常有用。Fetch API
和Ajax
在原生状态下不支持请求的取消和超时设置,需要手动编写实现。 API
的使用风格:Ajax
、Fetch
和Axios
在API
的使用风格上有所差异。Ajax
使用的是回调函数的方式,代码结构较为混乱,不易维护。Fetch API
使用Promise
的方式,代码结构清晰、易读、易维护。而Axios
同样使用Promise
的方式,但相对于Fetch API
来说,它的API
更为灵活,可以方便地进行扩展和定制。- 使用场景:
Ajax
、Fetch
和Axios
在不同的使用场景下有不同的优势。Ajax
的优势在于它是原生的浏览器API
,功能简单、易用、兼容性好,适合简单的异步请求场景。Fetch API
的优势在于它是Promise
风格的API
,支持流式传输、文件上传和下载等功能,适合复杂的异步请求场景。而Axios
的优势在于它是一个功能齐全、易用、灵活的请求库,支持请求和响应拦截器、请求的取消和超时、并发请求等功能,适合复杂的异步请求场景。
Ajax | Fetch API | Axios | |
基于Promise | 🛑(基于 XMLHttpRequest) | ✅ | ✅ |
兼容性 | ✅ 具有较好的兼容性,几乎可以在所有浏览器上运行 | 🟡 对于现代浏览器的兼容性更好 | 🟡 对于现代浏览器的兼容性更好 |
TypeScript支持 | 🛑 | 🟡 | ✅ |
数据缓存 | 🛑 | ✅ | ✅ |
自动重试 | 🛑 | ✅ | ✅ |
取消请求 | 🟡 原生不支持,需手动编写实现 | 🟡 原生不支持,需手动编写实现 | ✅ |
请求异常 | 🟡 在网络异常和超时处理方面需要手动编写实现 | 🟡 在网络异常和超时处理方面需要手动编写实现 | ✅ 提供了更好的网络异常处理机制,可以方便地处理网络异常和超时异常 |
超时时间 | 🛑 | 🛑 | ✅ |
跨域 | 🟡 原生不支持跨域请求,需手动实现(如JSONP) | ✅ | ✅ |
错误处理 | 🟡 原生对于错误处理和状态码处理的支持相对较少 | 🟡 原生对于错误处理和状态码处理的支持相对较少 | ✅ 提供了丰富的错误处理和状态码处理的功能 |
请求响应拦截 | 🛑 | 🟡 | ✅(全局) |
并发请求 | ✅ | 🟡 原生不支持并发请求,需要手动编写实现 | ✅ |
数据转换 | 🟡 原生状态下需要手动将响应数据转换为 JavaScript 对象 | 🟡 原生状态下需要手动将响应数据转换为 JavaScript 对象 | ✅ 可以自动将响应数据转换为 JavaScript 对象 |
序列化参数 | ✅ 使用 URLSearchParams | 🟡 原生不支持 URLSearchParams 对象,需要手动编写实现 | ✅ 使用 URLSearchParams |
文件处理 | 🟡 原生不支持文件上传和下载,需要手动编写实现 | 🟡 原生不支持文件上传和下载,需要手动编写实现 | ✅ |
插件机制 | 🟡 在扩展性方面相对较差,需要手动编写实现 | 🟡 在扩展性方面相对较差,需要手动编写实现 | ✅ 支持自定义拦截器、转换器、扩展请求和响应等功能 |
数据格式 | 🟡 对数据格式的支持相对较少,需要手动编写实现 | 🟡 对数据格式的支持相对较少,需要手动编写实现 | ✅ 支持多种数据格式的请求和响应,包括 JSON、URL-encoded、XML、HTML、Text 等 |
headers验证 | 🛑 | ✅ 支持通过 request.credentials 属性来控制请求是否携带 cookies 和 cors 相关的头部信息 | ✅ 可以使用 withCredentials 配置选项来控制请求是否携带 cookies 和 cors 相关的头部信息 |