数据之桥:Fetch / Ajax 与前后端通信

当网页需要加载商品、提交表单或刷新评论时,必须与服务器进行通信。这种“不刷新页面即可获取数据并更新界面”的能力,是现代 Web 开发的核心。本文将重点讲解前端如何主动发起 HTTP 请求,并把数据渲染到页面上。


1. 为什么需要前后端通信?

网页内容通常是动态获取的(如电商列表、用户昵称、评论等)。前端负责界面交互与渲染,后端负责业务逻辑与数据存储,两者最常见的沟通方式就是 HTTP 接口通信

2. 什么是 Ajax?

Ajax(Asynchronous JavaScript and XML)是一种开发思想:使用 JavaScript 在后台发请求,并在不刷新页面的情况下局部更新内容。 它并非特定 API,常见实现包括早期的 XMLHttpRequest、现代浏览器原生的 fetch 以及第三方库 axios


3. Fetch 基础使用

fetch 是浏览器原生 API,基于 Promise,推荐配合 async/await 使用,语法更加现代。

3.1 发送 GET 请求

async function getData() {
  try {
    // 发起 GET 请求
    const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    // 把响应体解析成 JSON
    const data = await response.json(); // 解析为 JSON
    console.log(data);
  } catch (error) {
    console.error("网络错误:", error);
  }
}

3.2 发送 POST 请求与携带参数

async function postData() {
  try {
    const response = await fetch("https://api.example.com/users", {
      // 指定请求方法
      method: "POST",
      headers: {
        "Content-Type": "application/json" // 声明发送的数据格式
      },
      body: JSON.stringify({ username: "alice", password: "123" }) // 提交的数据体
    });
    const data = await response.json();
    console.log("创建结果:", data);
  } catch (error) {
    console.error("提交失败:", error);
  }
}

4. 避坑:Response 对象与错误处理

fetch() 返回的并非最终数据,而是一个 Response 对象,包含 status (状态码)、ok (是否成功) 等信息。 核心坑点: 即使服务器返回 404500fetch 也不会进入 catch(只有断网等网络层错误才会)。因此必须手动检查 response.ok

const response = await fetch("https://api.example.com/data");

// fetch 遇到 404/500 不会自动抛错,需要自己判断
if (!response.ok) {
  throw new Error(`请求失败,状态码:${response.status}`);
}

// 确认成功后再读取数据
const data = await response.json();

5. 完整实战:数据渲染与状态处理

真实项目中,请求接口必须处理 加载中、成功(含空数据)、失败 三种状态。

<div id="app"></div>

<script>
  async function loadArticles() {
    const app = document.getElementById("app");
    app.innerHTML = "加载中..."; // 1. 加载状态

    try {
      const res = await fetch("https://jsonplaceholder.typicode.com/posts");
      if (!res.ok) throw new Error("加载失败");
      
      // 把响应结果解析成数组
      const articles = await res.json();
      
      if (articles.length === 0) {
        app.innerHTML = "暂无数据"; // 2. 空状态
        return;
      }
      
      // 3. 成功渲染
      app.innerHTML = articles.slice(0, 5).map(a => `<p>${a.title}</p>`).join("");
    } catch (error) {
      app.innerHTML = `请求错误:${error.message}`; // 4. 错误状态
    }
  }

  loadArticles();
</script>

6. 传统 Ajax (XMLHttpRequest) 核心知识

为了扎实基础,理解传统的 XHR 是必不可少的。它通过事件和状态码管理请求。

6.1 XHR 生命周期 (readyState)

  • 0 (UNSENT):未初始化。已创建 XHR 对象,未调用 open()
  • 1 (OPENED):已打开。已调用 open(),未调用 send()
  • 2 (HEADERS_RECEIVED):已接收响应头。
  • 3 (LOADING):正在下载响应体。
  • 4 (DONE):请求完成。

6.2 经典封装与 Fetch 的区别

传统 XHR 依赖回调(如 onreadystatechangeonload),易产生回调地狱。现代开发常用 Promise 封装 XHR(这也是 axios 的底层原理)。 相比 XHR,fetch 的核心优势在于:

  1. 语法更简洁:基于 Promise,契合 async/await
  2. 关注点分离:请求与响应头/体解析分离,更加语义化。
  3. 默认不带 Cookie:跨域默认不携带凭证,需显式配置。

7. 常见配置与排错指南

7.1 常见请求配置

  • 请求头配置:常用于传递 Token(Authorization: Bearer <token>)。
  • 超时控制:原生 fetch 需结合 AbortController 实现;若业务复杂,推荐直接使用 axios

7.2 常见接口问题

  • 跨域拦截:需后端配置 CORS 允许跨域。
  • 401 / 403:未登录或身份失效 / 无权限访问。
  • 404 / 500:接口地址错误 / 服务器内部异常。
  • 数据格式报错:养成先 console.log(data) 看清返回结构的习惯。

8. 总结:Fetch、Ajax 与 Axios

  • Ajax:一种“异步请求数据、局部更新页面”的开发思想
  • fetch:现代浏览器原生的具体 API
  • axios:基于 Promise 封装的第三方库,项目中最为常见。

掌握 HTTP 请求流程和 DOM 渲染后,网页才真正具备了连接真实业务数据的能力。接下来,即可平滑过渡到 Vue/React 等现代框架的工程化开发中。