JS fetch接口请求实战指南

2025-12-27 9758阅读

在现代Web开发中,与后端接口的数据交互是核心环节。从早期的XMLHttpRequest到如今的fetch API,前端请求方式不断演进。fetch作为原生浏览器API,凭借简洁的Promise语法和灵活的配置能力,逐渐成为异步请求的首选方案。本文将从基础用法到高级技巧,全面解析JS fetch接口请求的实战要点,帮助开发者高效处理数据交互。

一、fetch基础用法:从入门到掌握

fetch()是浏览器原生提供的接口请求方法,调用时返回一个Promise对象,处理异步请求结果。基础语法如下:

// GET请求示例:获取用户列表
fetch('https://api.example.com/users')
  .then(response => {
    // 处理响应数据
    if (!response.ok) {
      throw new Error(`请求失败,状态码:${response.status}`);
    }
    return response.json(); // 解析JSON格式响应
  })
  .then(data => console.log('用户数据:', data))
  .catch(error => console.error('请求错误:', error.message));

核心参数解析
fetch(url, init)的第二个参数init是可选配置对象,包含请求方法、头信息、请求体等:

  • method:请求方法(GET/POST/PUT/DELETE等)
  • headers:请求头(如Content-Type、Token、Cookie)
  • body:请求体(仅POST/PUT等方法使用,需为字符串或FormData等)
  • credentials:是否携带Cookie(same-origin/cors/include)

POST请求示例:发送JSON数据到服务器

const userData = { name: '张三', age: 25 };
fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json', // 声明JSON格式
    'Authorization': 'Bearer YOUR_TOKEN' // 身份验证
  },
  body: JSON.stringify(userData) // 请求体需转为JSON字符串
})
.then(response => response.json())
.then(result => console.log('创建用户成功:', result));

二、常见场景:解决90%的接口请求问题

1. 请求参数传递

  • GET请求参数:直接拼接URL(查询字符串)
    const userId = 1;
    fetch(`https://api.example.com/users/${userId}?include=posts`)
  • POST请求数据格式:支持JSON、FormData、URLSearchParams等
    • FormData(上传文件或表单数据):
      const formData = new FormData();
      formData.append('avatar', fileInput.files[0]); // 添加文件
      formData.append('username', 'test'); // 添加文本
      fetch('https://api.example.com/upload', {
      method: 'POST',
      body: formData // FormData无需手动设置Content-Type
      });

2. 错误处理:避免请求“静默失败”

fetch仅在网络故障时抛出错误,HTTP错误(如404、500)需手动判断:

fetch('https://api.example.com/data')
  .then(response => {
    // 手动处理HTTP错误状态码
    if (!response.ok) {
      if (response.status === 401) {
        // 未授权:跳转登录页
        window.location.href = '/login';
      }
      throw new Error(`HTTP错误:${response.status}`);
    }
    return response.json();
  })
  .catch(error => {
    if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {
      // 网络错误:提示用户检查连接
      alert('网络连接失败,请重试');
    }
  });

3. 异步/同步语法:async/await简化代码

结合async/await可将异步代码写得更接近同步逻辑:

async function getUserData(userId) {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const user = await response.json();
    return user; // 返回结果供上层调用
  } catch (error) {
    console.error('获取用户数据失败:', error);
    return null; // 错误时返回默认值
  }
}

// 使用示例
getUserData(1).then(user => console.log('用户信息:', user));

三、高级技巧:突破基础限制的实战能力

1. 中断请求:AbortController的应用

当用户离开页面、组件卸载或请求超时后,可通过AbortController取消请求:

const controller = new AbortController();
const signal = controller.signal;

// 发起请求时传入signal
const fetchData = fetch('https://api.example.com/large-data', { signal });

// 取消请求(如用户点击“取消”按钮)
document.getElementById('cancel-btn').addEventListener('click', () => {
  controller.abort(); // 终止请求
  console.log('请求已取消');
});

fetchData.catch(error => {
  if (error.name === 'AbortError') {
    // 捕获取消错误
    console.log('请求被主动取消');
  }
});

2. 请求拦截与封装:统一处理通用逻辑

通过封装fetch函数,可实现Token自动添加、错误重试、日志打印等通用逻辑:

function fetchWithAuth(url, options = {}) {
  // 1. 自动添加Token
  const token = localStorage.getItem('token');
  const headers = {
    'Content-Type': 'application/json',
    ...options.headers,
    ...(token && { 'Authorization': `Bearer ${token}` })
  };

  return fetch(url, { ...options, headers })
    .then(response => {
      // 2. 统一错误状态码处理
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return response.json();
    })
    .catch(error => {
      // 3. 错误重试(示例:网络错误时重试1次)
      if (error.name === 'TypeError' && options.retry) {
        return fetchWithAuth(url, { ...options, retry: false });
      }
      return Promise.reject(error);
    });
}

// 使用示例
fetchWithAuth('https://api.example.com/data', { method: 'GET' });

3. 并发请求:Promise.all的高效应用

当需要同时获取多个接口数据时,使用Promise.all并行请求:

async function loadDashboardData() {
  const [userResponse, statsResponse] = await Promise.all([
    fetch('https://api.example.com/dashboard/user'),
    fetch('https://api.example.com/dashboard/stats')
  ]);
  const user = await userResponse.json();
  const stats = await statsResponse.json();
  return { user, stats }; // 聚合结果
}

loadDashboardData().then(data => console.log('仪表盘数据:', data));

四、最佳实践:让请求更健壮、更高效

1. 错误分类与用户体验

  • 网络错误:提示“网络连接失败,请检查网络设置”
  • 401未授权:自动跳转登录页
  • 404资源不存在:显示“数据不存在”提示
  • 500服务器错误:提示“服务器维护,请稍后重试”

2. 请求合并与节流

对高频触发的请求(如搜索输入),使用防抖/节流减少请求次数:

// 防抖函数:300ms内只触发一次请求
function debounceFetch(url, delay = 300) {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      fetch(url, ...args);
    }, delay);
  };
}

const searchFetch = debounceFetch('https://api.example.com/search');
// 输入事件触发时调用searchFetch
input.addEventListener('input', (e) => searchFetch(e.target.value));

3. 响应缓存:提升性能的关键

结合Cache API缓存请求结果,避免重复请求:


async function fetchWithCache(url) {
  const cacheKey = `cache_${url}`;
  const cachedData = localStorage.getItem(cacheKey);

  // 优先读取缓存
  if (cachedData) {
    return JSON.parse(cachedData);
  }

  // 缓存未命中时请求接口
  const response = await fetch(url);
  const data = await response.json();

  // 存入缓存(设置10分钟过期)
  localStorage.setItem(cacheKey,
文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

目录[+]