使用Fetch API 探索前后端数据交互

前言

在当今的 Web 开发中,前端与后端的数据交互是构建动态应用的核心。API 是连接不同软件应用的重要桥梁,允许开发者通过 HTTP 请求与服务器交互,高效调用API数据对于构建现代 Web 应用至关重要。传统的页面刷新方式已经无法满足用户对流畅体验的需求,而 Fetch API 的出现为 JavaScript 带来了全新的生命力。

一、Fetch API 概述

1.1 Fetch API 是什么❓

Fetch API 是现代浏览器提供的一个用于发起网络请求的接口,用于发起 HTTP 请求。它提供简洁的异步API,使开发者能够以更现代的方式与服务器交互。它是传统的 XMLHttpRequest 的替代品,提供了更简洁、更强大的功能。基于 Promise 实现,使异步操作更加直观。

相比于传统的 XMLHttpRequest 更加强大、灵活且易于使用。Fetch 基于 Promise 设计,使得异步请求的处理更加优雅。

特性 Fetch API XMLHttpRequest
语法 基于 Promise,更简洁 回调函数,较复杂
请求/响应对象 标准化 非标准化
默认携带 Cookie 不携带 携带
超时控制 需要额外实现 原生支持
取消请求 使用 AbortController 原生支持
进度事件 有限支持 完整支持

1.2 Fetch 的基本语法

Fetch API 的基本用法是通过调用 fetch() 函数并传入一个 URL 作为参数来发起网络请求。该函数返回一个Promise对象,可以在其then()方法中处理请求成功的情况,在catch()方法中处理请求失败的情况。Fetch API 最基本的形式如下所示。

javascript 复制代码
fetch(url, options)
	.then(response => response.json()) // 解析 JSON 数据
  .then(data => console.log(data))   // 处理数据
	.catch(error => console.error('出现错误:', error)); // 错误处理

上述代码示例展示了使用 Fetch API 发起一个请求,返回的 Promise 解析为响应对象,进而能访问响应体数据。处理响应体通常包含 JSON 数据,通过 .json() 方法解析。如果请求失败,fetch 返回的 promise 会拒绝,并将错误信息传给 catch 方法。

1.3 fetch 配置选项

fetch 接受第二个可选参数,一个可以控制不同配置的对象,常见属性如下表所示。

配置项 简要描述 常用值
method 请求的 HTTP 方法,默认方法为GET GET、POST、PUT、PATCH、DELETE
headers 请求中 HTTP 标头
body 请求体。 请注意,使用 GET 和 HEAD 方法的请求不能有正文
mode 指定请求的模式。 cors:默认值,允许跨域请求 same-origin:只允许同源请求。 no-cors:不能添加跨域的复杂标头,相当于提交表单所能发出的请求
credentials 指定是否发送 Cookie same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送 include:不管同源请求,还是跨域请求,一律发送 Cookie omit:一律不发送
cache 指定如何处理缓存 default:默认值,先在缓存里面寻找匹配的请求 no-store:直接请求远程服务器,并且不更新缓存 reload:直接请求远程服务器,并且更新缓存 no-cache: force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器 only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误
redirect 如何处理 HTTP 重定向响应,默认设置为follow follow、error、manual
referrer 包含请求的反向链接的字符串,默认为空字符串
referrerPolicy 指定用于请求的反向链接政策
signal AbortSignal 对象实例,支持接口中止请求
priority 指定当前请求相对于其他同类请求的优先级, 默认设置为auto high、low、auto

二、Fetch API 的基本使用

Fetch API 支持多种 HTTP 请求方法,如GET、POST、PUT、DELETE等。默认情况下,fetch() 函数会发送 GET 请求。如果需要发送其他类型的请求,可以在fetch() 函数的第二个参数中指定请求的配置对象。

2.1 发起 GET 请求

GET 请求是最常见的请求类型,用于从服务器获取数据。在Fetch API中,构造一个 GET 请求的URL是一件非常简单的事情。首先需要了解的是,GET请求的参数通常是通过URL的查询字符串(query string)部分传递给服务器的。

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

在上述例子中,fetch 执行 GET 请求,在构建URL时,需要确保查询参数是经过URL编码的,以避免查询字符串解析错误。一旦发起 GET 请求,就需要处理服务器返回的响应数据,Fetch API 返回的 response 是一个 Response 对象,可以使用以下任一方法获取响应内容:

方法 简要说明
response.text() 返回一个使用以文本为响应正文解析的 Promise
response.json() 返回一个使用从 JSON 响应中解析的对象解析的 Promise
response.blob() 返回一个使用以 Blob 对象为响应正文解析的 Promise
response.ArrayBuffer() 返回一个使用以 ArrayBuffer 实例为响应正文解析的 Promise
response.formData() 返回一个使用以 FormData 对象为响应正文解析的 Promise

2.2 发起 POST 请求

POST 请求用于向服务器发送数据,如提交表单或调用 API 提交数据到服务器。通过 Fetch API 调用 POST 请求需要构造一个包含请求体的对象,并将这个对象作为第二个参数传递给 fetch 函数。

javascript 复制代码
const userData = {
  username: 'example',
  email: 'example@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST',
  body: JSON.stringify(userData)
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('出现错误:', error));

使用 fetch() 发送 POST 请求的关键是指定要发送至服务器的数据,它可以采用多种格式,包括 JSON、FormData 和文本格式。在上述示例中,我们通过设置 method 为 POST 来发送 POST 请求,并在请求体 body 中发送 JSON 格式的数据。fetch 函数会将这些信息发送到服务器,并等待响应。

2.3 使用 async/await

Fetch API 支持 async/await 语法,可以更简洁地处理异步操作,如下所示。fetch 接收到的 response 是一个 Stream 对象,response.json() 是一个异步操作,取出所有内容,并将其转为 JSON 对象。

javascript 复制代码
const response = await fetch(url, options);
const data = await response.json();

三、Fetch API 的响应处理

3.1 处理 HTPP 响应

fetch 请求成功以后,得到的是一个 Response 对象,它对应服务器的 HTTP 响应。

javascript 复制代码
const res=await fetch(url)

Response 包含的数据通过 Stream 接口异步读取,但它还有一些同步属性,对应 HTTP 回应的标头信息(Headers),如下表所示。

标头属性 类型 简要说明
Response.ok boolean 表示请求是否成功,true 对应的 HTTP 请求状态码200-299,false对应其他的状态码
Response.status number 返回一个数字,表示HTTP响应的状态码
Response.statusText string 表示HTTP响应的状态信息,例如请求成功以后,服务器返回 OK
Response.url string 返回请求的URL。如果URL存在跳转,该属性返回的是最终的URL
Response.type string 返回的是请求的类型。可能为以下值:  basic:普通请求,即同源请求  cors:跨域请求  error:网络错误,主要用于Service Worker  opaque:如果fetch请求的type属性为no-cors,就会返回这个值,表示发出的是简单的跨域请求  opaqueredirect:如果fetch请求的redirect属性设为manual,就会返回这个值
Response.redirected boolean 表示请求是否有过重定向

3.2 处理请求响应状态

在处理请求响应时,我们首先检查响应状态是否成功(response.ok),如果不成功则抛出错误。fetch 发出请求后,只有网络错误或无法连接时才会报错,即使服务器返回的状态码 是4xx或5xx。只有通过 Response.status 属性得到 HTTP 响应的真实状态码时,才能判断请求是否成功。

javascript 复制代码
fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('网络请求错误,' + response.statusText);
    }
    return response.json();
  })
  .then(data => console.log('Success:', data))
  .catch(error => console.error('出现错误:', error));

3.3 处理不同的响应类型

当接收到服务器的响应后,通常需要解析响应体。Response 对象根据服务器返回的不同类型的数据,提供了不同的读取方法。这几个方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据。

方法 简要说明
response.text() 获取文本字符串,主要用于获取文本数据,比如 HTML 文件
response.json() 获取 JSON 对象,主要用于获取服务器返回的 JSON 数据
response.blob() 获取二进制 Blob 对象
response.formData() 获取 FormData 表单对象,主要用于拦截用户提交的表单,修改某些数据后再提交给服务器
response.arrayBuffer() 得到二进制 ArrayBuffer 对象,主要用于获取流媒体文件

Fetch API 可以处理多种响应格式:

javascript 复制代码
// 处理JSON响应
fetch('/api/data.json')
  .then(response => response.json())
  .then(data => console.log(data));

// 处理文本响应
fetch('/api/data.txt')
  .then(response => response.text())
  .then(text => console.log(text));

// 处理Blob响应(如图片)
fetch('/image.png')
  .then(response => response.blob())
  .then(blob => {
    const objectURL = URL.createObjectURL(blob);
    document.getElementById('image').src = objectURL;
  });

注意,Response 是一个 Stream 对象,而 Stream 对象只能读取一次,读取完就没了。这意味着,上面的几个读取方法,只能使用一个,否则会报错。

四、高级 Fetch 用法

4.1 设置请求头

在使用Fetch API进行请求时,可以通过 Headers 对象来设置请求头。每个请求或响应都有一个与之关联的 Headers 对象,这个对象包含了请求头和响应头,例如 Content-Type、Authorization 等。

javascript 复制代码
fetch('https://example.com/api', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer your-token'
    },
    body: JSON.stringify({ name: 'John', age: 30 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('出现错误:', error));

Response 对象还有一个 Response.headers 属性,指向一个Headers 对象,对应HTTP响应的所有标头。Headers 对象提供了以下方法来操作标头:

方法 简要说明
Headers.get() 根据指定的键名,返回键值
Headers.has() 返回一个布尔值,表示是否包含某个标头
Headers.set() 将指定的键名设置为新的键值,如果该键名不存在则会添加
Headers.append() 添加标头
Headers.delete() 删除标头
Headers.keys() 返回一个遍历器,可以依次遍历所有键名
Headers.values() 返回一个遍历器,可以依次遍历所有键值
Headers.entries() 返回一个遍历器,可以依次遍历所有键值对([key, value])
Headers.forEach() 依次遍历标头,每个标头都会执行一次参数函数

上面的有些方法可以修改标头,那是因为继承自 Headers 接口。有些标头不能通过headers属性设置,比如Content-Length、Cookie 、Host等等。它们是由浏览器自动生成,无法修改。这些方法中,最常用的是 response.headers.get(),用于读取某个标头的值。

javascript 复制代码
let response =  await  fetch(url);  
response.headers.get('Content-Type')

4.2 设置请求体参数

当需要发送POST请求时,经常需要向服务器发送一些数据。使用Fetch API可以很便捷地通过 body 属性发送请求体。

javascript 复制代码
// 发送JSON数据
const data = JSON.stringify({ name: 'John', age: 30 });
 
const options = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: data
};
 
fetch('https://example.com/api/users', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
 
// 发送表单数据
const formdata = new FormData();
formdata.append('username', 'john');
formdata.append('email', 'john@example.com');
 
fetch('https://example.com/api/register', {
  method: 'POST',
  body: formdata
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

4.3 设置请求超时

Fetch API 本身不支持超时设置,但可以通过 AbortController 实现:

javascript 复制代码
const controller = new AbortController();
const signal = controller.signal;

// 设置5秒超时
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://api.example.com/data', { signal })
  .then(response => response.json())
  .then(data => {
    clearTimeout(timeoutId);
    console.log(data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Request timed out');
    } else {
      console.error('Other error:', error);
    }
  });

4.4 跨域请求

如果需要进行跨域请求,可以在服务器端设置 CORS(Cross-Origin Resource Sharing)。在前端,也可以通过 credentials 选项来指定是否发送 cookies 等凭据。

javascript 复制代码
fetch('https://example.com/api', {
    method: 'GET',
    credentials: 'include' // 允许跨域请求时携带 cookie
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('出现错误:', error));

4.5 上传文件

如果表单里面有文件选择器,使用 Fetch 上传文件时,可以构造出一个表单,进行上传。

javascript 复制代码
const fileInput = document.querySelector('input[type="file"]');

const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('username', 'exampleUser');

fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData
  // 注意:不要手动设置Content-Type头,浏览器会自动设置正确的boundary
})
.then(response => response.json())
.then(data => console.log('Upload success:', data))
.catch(error => console.error('Upload error:', error));

4.6 请求取消

使用 AbortController 取消正在进行的请求:

javascript 复制代码
const controller = new AbortController();

// 开始请求
fetch('https://api.example.com/data', {
  signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
  if (error.name === 'AbortError') {
    console.log('Request was aborted');
  } else {
    console.error('Error:', error);
  }
});

// 在某个事件中取消请求
document.getElementById('cancel-button').addEventListener('click', () => {
  controller.abort();
});

4.7 并发请求

使用 Promise.all 处理多个并发请求:

javascript 复制代码
async function fetchMultipleResources() {
  try {
    const [usersResponse, postsResponse] = await Promise.all([
      fetch('https://api.example.com/users'),
      fetch('https://api.example.com/posts')
    ]);

    if (!usersResponse.ok || !postsResponse.ok) {
      throw new Error('One or more requests failed');
    }

    const users = await usersResponse.json();
    const posts = await postsResponse.json();

    console.log('Users:', users);
    console.log('Posts:', posts);

    // 合并数据并更新UI
    displayCombinedData(users, posts);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

function displayCombinedData(users, posts) {
  // 实现数据合并和显示逻辑
}

五、总结

Fetch API 是一个强大而简洁的网络请求 API,它基于 Promise 实现,提供了更好的可读性和可维护性。通过学习和掌握 Fetch API 的基本用法和请求方法,我们可以更轻松地发起网络请求并处理响应结果。同时,我们也需要注意 Fetch API 的一些限制和常见问题,并采取相应的措施来解决它们。

相关推荐
css趣多多2 小时前
别名路径的知识点
前端
靓仔建4 小时前
Vue3导入组件出错does not provide an export named ‘user_setting‘ (at index.vue:180:10)
开发语言·前端·typescript
EnoYao4 小时前
我写了一个团队体检报告 Skill,把摸鱼的同事扒出来了😅
前端·javascript
梁正雄4 小时前
Python前端-2-css练习
前端·css·python
清汤饺子4 小时前
用 Cursor 半年了,效率还是没提升?是因为你没用对这 7 个功能
前端·后端·cursor
蓝莓味的口香糖4 小时前
【vue3】组件的批量全局注册
前端·javascript·vue.js
wefly20174 小时前
开发者效率神器!jsontop.cn一站式工具集,覆盖开发全流程高频需求
前端·后端·python·django·flask·前端开发工具·后端开发工具
独泪了无痕5 小时前
自动导入 AutoImport:告别手动引入依赖,优化Vue3开发体验
前端·vue.js·typescript
GDAL5 小时前
MANIFEST.in简介
linux·服务器·前端·python