前端网络请求:从 Ajax 到 Fetch,轻松搞定接口数据交互

在前端开发中,和后端接口打交道是家常便饭。无论是获取用户信息、提交表单数据,还是加载动态列表,都离不开网络请求。今天我们就从最基础的XMLHttpRequest(Ajax 的核心)讲起,再到现代的Fetch API,带你一步步掌握前端接口调用的核心用法,让你轻松实现数据交互。


一、先搞懂:Ajax 到底是什么?

很多人常说的 “发 Ajax 请求”,本质上是使用XMLHttpRequest(简称 XHR)对象发起的异步网络请求。它的核心优势是异步—— 不用刷新整个页面,就能和服务器交换数据、更新页面内容,这也是现代网页 “无刷新交互” 的基础。

1. 原生 Ajax(XMLHttpRequest)完整示例

我们先写一个完整的 GET 请求示例,再拆解每一步的作用:

javascript

// 1. 创建XMLHttpRequest对象
const xhr = new XMLHttpRequest();

// 2. 配置请求方式、接口地址和是否异步
// 参数1:请求方法(GET/POST等),参数2:接口URL,参数3:是否异步(默认true)
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);

// 3. 设置请求头(可选,比如发送JSON数据时需要设置Content-Type)
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');

// 4. 监听请求状态变化
xhr.onreadystatechange = function() {
  // readyState=4 表示请求已完成,status=200 表示请求成功
  if (xhr.readyState === 4 && xhr.status === 200) {
    // 解析响应数据(接口返回的是JSON字符串,需要转成JS对象)
    const response = JSON.parse(xhr.responseText);
    console.log('请求成功,数据:', response);
  } else if (xhr.readyState === 4) {
    // 请求完成但状态码不是200,说明请求失败
    console.error('请求失败,状态码:', xhr.status);
  }
};

// 5. 发送请求(GET请求可以不传参数,POST请求需要传入数据)
xhr.send();
关键步骤拆解:
  • new XMLHttpRequest():创建请求对象,这是所有操作的起点。
  • open(method, url, async):配置请求的基本信息,async默认true表示异步请求(不会阻塞页面其他代码执行)。
  • onreadystatechange:监听请求的状态变化,readyState有 5 个状态:
    • 0:未初始化,还没调用open()
    • 1:已打开,调用了open()但还没发送请求
    • 2:已发送,调用了send(),响应头已接收
    • 3:接收中,正在接收响应体数据
    • 4:请求完成,数据接收完毕
  • send():发送请求。如果是 POST 请求,需要把数据作为参数传入:

    javascript

    // POST请求示例
    const postData = { title: '新文章', content: '测试数据' };
    xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
    xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
    // 数据需要转成JSON字符串发送
    xhr.send(JSON.stringify(postData));
    

2. 原生 Ajax 的优缺点

✅ 优点:兼容性极强,几乎所有浏览器都支持,不需要引入额外库。

❌ 缺点:

  • 回调嵌套容易形成 “回调地狱”(多个请求依赖时,代码嵌套层级深,难以维护);
  • API 设计比较老旧,事件监听的方式写起来繁琐;
  • 没有内置的 Promise 支持,处理异步逻辑不够优雅。

二、现代方案:Fetch API,更简洁的异步请求

为了解决 Ajax 的痛点,ES6 推出了基于 Promise 的Fetch API,它的语法更简洁,支持链式调用,是现在前端网络请求的主流方案之一。

1. 基础 GET 请求示例

javascript

// 调用fetch方法,传入接口URL,默认是GET请求
fetch('https://jsonplaceholder.typicode.com/posts/1')
  // 第一个.then处理响应,先判断请求是否成功,再解析JSON数据
  .then(response => {
    // fetch的状态码判断:只有网络错误时才会reject,HTTP错误(如404/500)会进入resolve
    if (!response.ok) {
      throw new Error(`HTTP错误,状态码:${response.status}`);
    }
    // response.json()会把响应体解析成JS对象,返回一个Promise
    return response.json();
  })
  // 第二个.then处理解析后的数据
  .then(data => {
    console.log('Fetch GET请求成功,数据:', data);
  })
  // 捕获请求过程中的所有错误(网络错误、HTTP错误、解析错误)
  .catch(error => {
    console.error('请求失败:', error.message);
  });

2. POST 请求示例

javascript

const postData = {
  title: 'Fetch提交的文章',
  body: '这是用Fetch发送POST请求的测试数据',
  userId: 1
};

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST', // 指定请求方法
  headers: {
    'Content-Type': 'application/json;charset=utf-8', // 告诉服务器发送的是JSON数据
  },
  body: JSON.stringify(postData) // 数据需要转成JSON字符串
})
.then(response => {
  if (!response.ok) {
    throw new Error(`请求失败,状态码:${response.status}`);
  }
  return response.json();
})
.then(data => {
  console.log('Fetch POST请求成功,返回数据:', data);
})
.catch(error => {
  console.error('请求出错:', error);
});

3. 用 async/await 优化 Fetch 代码

Promise 的链式调用虽然比回调地狱好很多,但多个请求时还是不够直观。搭配 ES7 的async/await,可以把异步代码写成同步的形式,可读性拉满:

javascript

// 封装成async函数
async function fetchPostData() {
  try {
    // 1. 发送GET请求,await会等待Promise完成
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    
    // 2. 判断请求是否成功
    if (!response.ok) {
      throw new Error(`HTTP错误,状态码:${response.status}`);
    }
    
    // 3. 解析响应数据
    const data = await response.json();
    console.log('async/await GET请求成功:', data);
    
    // 4. 发送POST请求
    const postResponse = await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      body: JSON.stringify({ title: 'async/await提交', body: '测试数据', userId: 1 })
    });
    
    if (!postResponse.ok) {
      throw new Error(`POST请求失败,状态码:${postResponse.status}`);
    }
    
    const postResult = await postResponse.json();
    console.log('async/await POST请求成功:', postResult);
  } catch (error) {
    // 统一捕获所有错误
    console.error('请求过程出错:', error.message);
  }
}

// 调用函数
fetchPostData();

4. Fetch API 的优缺点

✅ 优点:

  • 语法简洁,基于 Promise,支持async/await,代码可读性高;
  • 是浏览器原生 API,不需要引入第三方库;
  • 支持更多现代特性(如流式响应、跨域配置)。

❌ 缺点:

  • 对低版本浏览器兼容性不如原生 XHR(不过现代浏览器都已支持);
  • 默认不携带 Cookie,需要手动配置credentials: 'include'
  • 没有内置的请求超时和取消机制(可以通过AbortController实现);
  • HTTP 错误状态码(如 404/500)不会触发reject,需要手动判断response.ok

三、Ajax vs Fetch:核心区别对比

为了帮你快速理解两者的差异,这里整理了一个对比表:

表格

特性原生 Ajax(XMLHttpRequest)Fetch API
语法风格回调函数 / 事件监听Promise 链式调用 + async/await
错误处理状态码判断 + 回调分支需手动判断response.ok,错误统一catch
浏览器兼容性所有浏览器兼容,包括低版本 IEIE 不支持,现代浏览器支持
Cookie 携带默认携带默认不携带,需配置credentials
超时 / 取消机制timeout属性和abort()方法需配合AbortController实现
代码简洁度繁琐,配置项多简洁,语义化强

四、实战小技巧:处理接口请求的常见问题

1. 实现请求超时(Fetch)

Fetch 本身没有超时配置,可以用Promise.race实现:

javascript

function fetchWithTimeout(url, options = {}, timeout = 5000) {
  // 创建一个超时的Promise,5秒后reject
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('请求超时')), timeout);
  });
  // Promise.race会返回第一个完成的Promise的结果
  return Promise.race([fetch(url, options), timeoutPromise]);
}

// 使用示例
async function testTimeout() {
  try {
    const response = await fetchWithTimeout('https://jsonplaceholder.typicode.com/posts/1', {}, 3000);
    const data = await response.json();
    console.log('数据:', data);
  } catch (error) {
    console.error(error.message);
  }
}

2. 取消请求(Fetch)

使用AbortController可以随时取消正在进行的请求:

javascript

async function fetchWithCancel() {
  const controller = new AbortController();
  const signal = controller.signal;

  // 3秒后取消请求
  setTimeout(() => controller.abort(), 3000);

  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1', { signal });
    const data = await response.json();
    console.log('数据:', data);
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('请求已被取消');
    } else {
      console.error('请求出错:', error);
    }
  }
}

3. 跨域请求配置

如果后端配置了 CORS,Fetch 请求可以直接跨域;如果是携带 Cookie 的跨域请求,需要配置credentials: 'include'

javascript

fetch('https://跨域接口地址', {
  method: 'GET',
  credentials: 'include' // 携带Cookie
})

五、总结:什么时候用 Ajax,什么时候用 Fetch?

  • 原生 Ajax:现在只有在兼容极老的浏览器(如 IE)时才会用到,日常开发基本不用手写原生 XHR 了。
  • Fetch API:现代项目中,搭配async/await使用,是轻量级接口请求的首选,不需要引入第三方库。
  • 大型项目中,我们更常用 Axios(基于 Promise 的 HTTP 客户端,封装了 XHR 和 Fetch 的优点,内置超时、拦截器、自动转换数据等功能),但理解 Ajax 和 Fetch 的底层原理,能帮你更好地使用这些封装库。

掌握了 Ajax 和 Fetch,你就掌握了前端和后端交互的核心能力,无论是单页应用还是普通网页,都能轻松实现数据的获取和提交。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值