http 请求-02-Ajax XHR 的替代方案 fetch api 入门介绍

http 请求系列

http request-01-XMLHttpRequest XHR 简单介绍

http request-01-XMLHttpRequest XHR 标准

Ajax 详解-01-AJAX(Asynchronous JavaScript and XML)入门介绍

Ajax XHR 的替代方案-fetch

Ajax XHR 的替代方案-fetch 标准

Ajax 的替代方案-axios.js

http 请求-04-promise 对象 + async/await

fetch

跨网络异步获取资源的功能以前是使用XMLHttpRequest对象实现的,Fetch API提供了更好的替代方案,可以很容易的被其他技术使用(如Servise Workers)

fetch,说白了,就是XMLHttpRequest的一种替代方案。

如果有人问你,除了Ajax获取后台数据之外,还有没有其他的替代方案?

你就可以回答,除了XMLHttpRequest对象来获取后台的数据之外,还可以使用一种更优的解决方案fetch。

fetch的支持性还不是很好,但是在谷歌浏览器中已经支持了fetch

返回 promise

Fetch API提供了一个全局的fetch()方法,该方法会返回一个Promise

当fetch请求接收到一个代表错误的状态码时(如404、500),返回的Promise不会被标记为reject,而是被标记为resolve,但是会将response的ok属性设置为false。

只有当网络错误或请求被阻止时才会被标记为reject状态

js 复制代码
fetch('https://127.0.0.1/125.jpg').then(function(res){
  if(res.ok) {
    return res.blob();
  }else {
    console.log('服务器响应出错了'); // 资源404、服务器500等
  }
}).catch(function(err){
  console.log('Network response was not ok.'); // 网络出错
})

为什么需要 js fetch,解决了 ajax 的什么问题?

fetch API 是为了解决传统的 XMLHttpRequest (XHR) 在使用过程中存在的一些问题和局限性。

fetch 提供了一个更现代化和简洁的方式来进行网络请求。

以下是 fetch 解决的一些 AJAX 的问题:

1. 更简洁的 API 设计

  • XHR : 使用 XMLHttpRequest 进行网络请求时,需要编写相对复杂和冗长的代码来处理各种情况。

设置请求方法、URL、请求头、监听状态变化等都需要多个步骤。

javascript 复制代码
  const xhr = new XMLHttpRequest();
  xhr.open('GET', 'https://api.example.com/data', true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log(JSON.parse(xhr.responseText));
    } else if (xhr.readyState === 4) {
      console.error('Request failed');
    }
  };
  xhr.send();
  • Fetch : fetch 通过一个简单的函数调用来实现相同的功能,并且支持 Promise,代码更简洁和易读。

    javascript 复制代码
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => console.log(data))
      .catch(error => console.error('Request failed', error));

2. 基于 Promise 的设计

  • XHR : XMLHttpRequest 的回调方式容易导致"回调地狱"(回调嵌套过多,代码难以维护)。虽然可以使用 Promise 包装 XHR,但这是额外的工作量。

  • Fetch : fetch 天生支持 Promise,使得处理异步操作更为自然和直观。它支持链式调用,可以很好地处理成功和错误的情况。结合 async/await,代码结构更加清晰。

    javascript 复制代码
    async function getData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error('Request failed', error);
      }
    }

3. 更好的流媒体支持

  • XHR : 对于处理流媒体或分块传输的数据,XMLHttpRequest 的处理方式较为复杂,需要手动操作数据块。

  • Fetch : fetch API 更好地支持 ReadableStream 和流媒体。你可以直接处理流媒体响应,逐块读取数据,这在处理大型文件或长连接时非常有用。

    javascript 复制代码
    fetch('https://example.com/stream')
      .then(response => {
        const reader = response.body.getReader();
        return reader.read();
      })
      .then(({ done, value }) => {
        if (!done) {
          console.log('Received chunk', value);
        }
      });

4. 内置的 JSON 处理

  • XHR : 使用 XMLHttpRequest 时,处理 JSON 数据需要手动解析。

    javascript 复制代码
    const data = JSON.parse(xhr.responseText);
  • Fetch : fetch 提供了 response.json() 方法,直接解析 JSON 数据,简化了代码。

    javascript 复制代码
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => console.log(data));

5. 默认行为更直观

  • XHR : 默认情况下,XMLHttpRequest 是异步的,但你必须显式地处理许多常见情况,比如跨域请求、超时等。

  • Fetch : fetch 的默认行为更符合现代 Web 开发需求,如遵循 CORS 标准、默认不发送 cookies 等。你可以通过选项轻松配置这些行为。

6. 更好的错误处理

  • XHR : XMLHttpRequest 只有在网络错误或请求被阻止时会触发 onerror,但它无法区分不同类型的错误,也无法轻松处理 HTTP 状态码。

  • Fetch : fetch 通过 Promise 进行错误处理,允许你更细粒度地控制请求的成功与失败。你可以轻松检查 HTTP 状态码并作出相应处理。

    javascript 复制代码
    fetch('https://api.example.com/data')
      .then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json();
      })
      .catch(error => console.error('Fetch error:', error));

总结

fetch 通过更简洁的 API、原生的 Promise 支持、内置的 JSON 处理、更好的流媒体支持,以及更直观的默认行为,解决了 XMLHttpRequest 在使用上的诸多不便,适合现代 JavaScript 开发需求。

fetch() 方法的两个参数

fetch()方法接收两个参数:第一个参数表示要获取的资源路径;第二个参数表示请求的配置项(可选)

js 复制代码
fetch('https://127.0.0.1/api/articles/1/3').then(function(res){
  if(res.ok) {
    return res.json();
  }
})

// 定义第二个参数
fetch('https://127.0.0.1/api/articles/1/3', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    token:'token'
  },
  cache: 'default',
  mode: 'cors',
}).then(function(res){
  if(res.ok) {
    return res.json();
  }
})

设置请求的头信息

在POST提交的过程中,一般是表单提交,可是,经过查询,发现默认的提交方式是:

Content-Type:text/plain;charset=UTF-8,这个显然是不合理的,改为 application/x-www-form-urlencoded

js 复制代码
fetch('https://www.baidu.com/search/error.html', {
    method: 'POST',
    headers: new Headers({
      'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式为表单提交
    }),
    body: new URLSearchParams([["foo", 1],["bar", 2]]).toString()
  })
  .then((res)=>{
    return res.text()
  })
  .then((res)=>{
    console.log(res)
  })

默认情况下, fetch 不会从服务端发送或接收任何 cookies,要发送 cookies,必须设置 credentials 选项

js 复制代码
fetch('http://127.0.0.1/search/name', {
  method: 'GET',
  credentials: 'include' // 强制加入凭据头
})
.then((res)=>{
  return res.text()
})

GET请求及传参

GET请求中如果需要传递参数怎么办?

这个时候,只能把参数写在URL上来进行传递了。

js 复制代码
fetch('http://127.0.0.1/search?a=1&b=2', { // 在URL中写上传递的参数
    method: 'GET'
  })
  .then((res)=>{
    return res.text()
  })

POST 请求及传参

POST请求的参数,放在第二个参数的body属性中

js 复制代码
fetch('http://127.0.0.1/searchs', { 
     method: 'POST',
    body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 这里是请求对象
  })
  .then((res)=>{
    return res.text()
  })

POST提交改为application/x-www-form-urlencoded

js 复制代码
fetch('http://127.0.0.1/searchs', { 
  method: 'POST',
  headers: new Headers({
    'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式为表单提交
  }),
  body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 这里是请求对象
})
.then((res)=>{
  return res.text()
})

fetch 的使用场景,有哪些优缺点?

使用场景

fetch API 在以下场景中非常适用:

  1. 简单的 HTTP 请求

    • 当需要向服务器发送简单的 GETPOSTPUTDELETE 请求时,fetch 是非常适合的选择。它简洁的语法使得处理这些请求变得直观。
  2. 处理 JSON 数据

    • fetch 内置了 response.json() 方法,特别适合从 API 获取 JSON 数据,并将其解析为 JavaScript 对象。
  3. 支持异步编程

    • 由于 fetch 基于 Promise,它适用于所有需要异步操作的场景,特别是在需要链式处理多个异步操作时,如连续的 API 请求。
  4. 流媒体或大文件处理

    • fetch 可以用于处理流媒体响应或大文件下载,通过 ReadableStream 逐块处理数据而不是一次性加载全部内容,减少内存占用。
  5. 跨域请求

    • fetch 默认遵循 CORS (Cross-Origin Resource Sharing) 规范,使其在处理跨域请求时更加安全和方便。
  6. 与现代浏览器兼容

    • fetch 在现代浏览器中得到广泛支持,对于不需要支持老旧浏览器的应用,fetch 是一个理想选择。

优点

  1. 简洁和现代化

    • fetch 的 API 设计简洁,代码更易读、维护性更高,符合现代 JavaScript 开发习惯。
  2. Promise-based

    • fetch 使用 Promise,支持 async/await,更容易处理异步代码,避免了回调地狱。
  3. 更好的错误处理

    • 可以通过 thencatch 来细粒度地处理请求结果和错误。
  4. 流式处理

    • 支持 ReadableStream,适合处理流媒体和大文件,能够逐步读取数据。
  5. 灵活的配置

    • fetch 允许通过选项灵活配置请求方法、头信息、请求体、缓存行为、跨域策略等,满足不同的需求。
  6. 内置 JSON 支持

    • 提供了 response.json() 等方法,简化了从服务器获取 JSON 数据并解析的流程。

缺点

  1. 不支持进度监听

    • fetch 不支持上传或下载的进度监听,这在处理大文件上传或下载时可能不够理想。如果需要进度反馈,可能需要回到 XMLHttpRequest 或使用第三方库。
  2. 没有内置超时处理

    • fetch 没有直接支持请求超时,开发者需要手动实现超时逻辑。这对于处理可能耗时过长的请求时增加了代码复杂性。
  3. 不自动抛出 HTTP 错误

    • 当服务器返回 4xx 或 5xx 状态码时,fetch 不会自动抛出错误,开发者需要手动检查 response.ok 属性并抛出错误。这与很多开发者的预期不同。
  4. 浏览器兼容性问题

    • 尽管大多数现代浏览器都支持 fetch,但是在较旧的浏览器(如 IE)中不支持,需要使用 polyfill 来保证兼容性。
  5. 跨域请求中的复杂性

    • 在处理跨域请求时,fetch 严格遵循 CORS 规范,有时会导致与服务器的交互变得复杂。如果后端没有正确配置 CORS,会导致请求失败。

总结

fetch 是一个功能强大且现代化的 API,适用于大多数网络请求场景。

它的简洁性和与现代异步编程模式的兼容性使其在新项目中非常受欢迎。

然而,对于某些高级需求,如进度监听或老旧浏览器支持,可能仍需考虑使用 XMLHttpRequest 或第三方库。

相关推荐
苏-言3 分钟前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
界面开发小八哥10 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
草莓base23 分钟前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Allen Bright37 分钟前
maven概述
java·maven
编程重生之路39 分钟前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端
薯条不要番茄酱39 分钟前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
努力进修1 小时前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list
politeboy1 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes
Daniel 大东2 小时前
BugJson因为json格式问题OOM怎么办
java·安全
Theodore_10226 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee