前端 HTTP 请求详解:从原生 AJAX、Fetch API 到 Axios(Go 后端开发者入门)
一、先搞清楚三个概念
你之前写 Go 后端,应该很熟悉下面这个场景:
前端调用后端接口:
bash
GET /api/users/1001
后端返回:
json
{
"id": 1001,
"name": "张三",
"age": 18
}
前端拿到数据之后,把用户名称显示到页面。
那么前端怎么发 HTTP 请求呢?
主要有三种方式:
- 原生 AJAX(XMLHttpRequest) :早期经典的 HTTP 请求方式。
- Fetch API:浏览器原生提供的现代 HTTP 请求接口。
- Axios:第三方 HTTP 请求库,对请求和响应做了进一步封装。
先看对比:
| 对比 | XMLHttpRequest | Fetch API | Axios |
|---|---|---|---|
| 是否浏览器原生 | 是 | 是 | 否,需安装 |
| 是否基于 Promise | 否,传统事件回调 | 是 | 是 |
| 是否支持 async/await | 需要自己封装 | 是 | 是 |
| JSON 响应处理 | 通常手动解析 | response.json() |
通常自动解析 |
| HTTP 404/500 | 需要检查状态码 | 不会自动 reject | 默认会 reject |
| 请求/响应拦截器 | 无内置机制 | 无内置机制 | 支持 |
| 使用复杂度 | 较高 | 较低 | 较低 |
现在开发 React 项目,重点掌握 Fetch API 和 Axios 即可。XMLHttpRequest 了解原理就行。
二、AJAX 到底是什么?
AJAX 全称:
Asynchronous JavaScript and XML
翻译:异步 JavaScript 和 XML。
虽然名字里面有 XML,但现在前后端通信主要使用 JSON。
1. 为什么需要 AJAX?
假设你访问一个用户管理页面,点击"查询用户"。
没有 AJAX 的传统页面交互方式可能是:
css
用户点击查询
↓
浏览器请求服务器
↓
服务器返回整个新 HTML 页面
↓
浏览器加载新页面
而 AJAX 可以做到:
javascript
用户点击查询
↓
JavaScript 发 HTTP 请求
↓
Go 后端返回 JSON
↓
JavaScript 获取数据
↓
更新页面中的用户信息
最大的区别:不需要为了获取新数据而重新加载整个网页。
注意,AJAX 是一种异步通信技术或开发方式,不是某一个具体的函数。
XMLHttpRequest、fetch()、Axios 都可以用于实现 AJAX 式的交互。
三、原生 AJAX:XMLHttpRequest
1. 最简单的 GET 请求
假设你的 Go 后端提供一个接口:
sql
GET /api/user/1001
返回:
json
{
"id": 1001,
"name": "张三"
}
前端代码:
javascript
const xhr = new XMLHttpRequest();
// 1. 配置请求
xhr.open("GET", "/api/user/1001");
// 2. 请求完成时执行
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
const user = JSON.parse(xhr.responseText);
console.log(user.name);
} else {
console.error("HTTP 请求失败", xhr.status);
}
};
// 3. 网络错误
xhr.onerror = () => {
console.error("网络错误");
};
// 4. 发送请求
xhr.send();
逐行解释。
第一步:创建请求对象
ini
const xhr = new XMLHttpRequest();
类似 Go 中准备一个 HTTP 请求相关对象。
第二步:配置请求
kotlin
xhr.open("GET", "/api/user/1001");
表示使用 GET 方法,请求 /api/user/1001。
第三步:注册回调函数
ini
xhr.onload = () => {
console.log(xhr.responseText);
};
这里很关键:onload 是一个回调函数,等请求完成后才执行。
第四步:发送请求
ini
xhr.send();
正式发送 HTTP 请求。
2. XMLHttpRequest 的问题
代码比较繁琐,需要自己处理:
- 请求状态。
- 成功和失败的回调。
- JSON 字符串解析。
- 网络错误和超时。
所以现代项目通常更倾向于 Fetch API 或 Axios。
四、Fetch API:现代浏览器原生请求方式
Fetch API 是浏览器内置的 HTTP 请求接口。
不需要通过 npm 安装依赖。
1. 最简单的 GET 请求
ini
fetch("/api/user/1001")
.then(response => response.json())
.then(user => {
console.log(user.name);
});
和 XMLHttpRequest 相比,明显简单了。
但是你前面学习过 Promise 和 async/await,可以写得更直观。
2. Fetch + async/await(推荐)
typescript
interface User {
id: number;
name: string;
}
async function getUser(): Promise<User> {
const response = await fetch("/api/user/1001");
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`);
}
const user: User = await response.json();
return user;
}
调用:
javascript
async function main() {
const user = await getUser();
console.log(user.name);
}
main();
这里有几个核心知识点。
① fetch()
scss
fetch("/api/user/1001")
表示向后端发送 HTTP 请求,默认是 GET 方法。
② await fetch()
ini
const response = await fetch("/api/user/1001");
fetch() 返回一个 Promise。
await 等待 HTTP 响应到达,得到 Response 对象。
③ response.json()
ini
const user = await response.json();
把响应体中的 JSON 解析为 JavaScript 数据。
注意:response.json() 本身也是异步的,因此要使用 await。
④ response.ok
javascript
if (!response.ok) {
throw new Error("请求失败");
}
fetch() 遇到 HTTP 404、500 时,通常不会自动抛出异常。
因此需要自己检查 HTTP 状态。
3. Fetch POST 请求
假设后端提供:
bash
POST /api/user
Content-Type: application/json
请求参数:
json
{
"name": "张三",
"age": 18
}
Fetch 写法:
php
async function createUser() {
const response = await fetch("/api/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "张三",
age: 18
})
});
if (!response.ok) {
throw new Error("创建失败");
}
return response.json();
}
这里:
method:HTTP 方法。headers:请求头。body:请求体。JSON.stringify():把 JavaScript 对象转换为 JSON 字符串。
4. 与 Go HTTP Client 对比
Go:
css
data := map[string]any{
"name": "张三",
"age": 18,
}
body, _ := json.Marshal(data)
req, _ := http.NewRequest(
"POST",
"http://localhost:8080/api/user",
bytes.NewReader(body),
)
req.Header.Set("Content-Type", "application/json")
TypeScript:
php
const response = await fetch("/api/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "张三",
age: 18
})
});
两段代码的思路基本一致。
五、Axios:第三方 HTTP 请求库
Axios 是一个基于 Promise 的 HTTP 客户端。
可以在浏览器和 Node.js 环境中使用。
相比 Fetch,它提供了很多开箱即用的功能,例如:
- 自动处理常见 JSON 响应。
- 请求和响应拦截器。
- 默认 HTTP 错误状态处理。
- 统一配置请求地址、请求头等。
1. 安装 Axios
npm:
npm install axios
pnpm:
csharp
pnpm add axios
然后导入:
javascript
import axios from "axios";
2. Axios GET 请求
typescript
import axios from "axios";
interface User {
id: number;
name: string;
}
async function getUser(): Promise<User> {
const response = await axios.get<User>("/api/user/1001");
return response.data;
}
调用:
javascript
async function main() {
const user = await getUser();
console.log(user.name);
}
main();
重点看:
csharp
axios.get<User>("/api/user/1001")
这里的 <User> 是你前面学过的 TypeScript 泛型。
它告诉 TypeScript:这个接口的响应数据按 User 类型处理。
注意:这个泛型只负责静态类型检查,不能保证服务器真的返回符合 User 结构的数据。
3. Axios POST 请求
csharp
async function createUser() {
const response = await axios.post("/api/user", {
name: "张三",
age: 18
});
return response.data;
}
和 Fetch 对比:
Fetch:
css
await fetch("/api/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "张三",
age: 18
})
});
Axios:
php
await axios.post("/api/user", {
name: "张三",
age: 18
});
Axios 会帮你处理常见的 JSON 请求体序列化和对应请求头。
4. Axios 最重要的区别:response.data
Fetch:
ini
const response = await fetch("/api/user/1001");
const user = await response.json();
Axios:
ini
const response = await axios.get("/api/user/1001");
const user = response.data;
注意:
Fetch 的 response.json() 是异步方法,Axios 的 response.data 是已经处理好的响应数据。
六、Axios 的实际项目用法
真实业务中,一般不会在每个地方都重新写完整的请求配置。
而是统一封装 HTTP 客户端。
1. 创建 Axios 实例
javascript
// request.ts
import axios from "axios";
export const request = axios.create({
baseURL: "/api",
timeout: 10000
});
这里:
baseURL:接口基础路径。timeout:请求超时时间,单位毫秒。
例如:
vbscript
request.get("/users");
对应的请求路径是:
bash
/api/users
2. 请求拦截器
ini
request.interceptors.request.use(config => {
const token = sessionStorage.getItem("token");
if (token) {
config.headers.set("Authorization", `Bearer ${token}`);
}
return config;
});
请求拦截器的作用是:
在真正发送 HTTP 请求之前,对请求配置进行统一处理。
例如自动添加认证信息、请求 ID 等。
这里仅展示机制。生产环境中 Token 的存储与传递应遵循项目既有的安全方案。
3. 响应拦截器
vbscript
request.interceptors.response.use(
response => {
return response;
},
error => {
console.error("请求失败", error);
return Promise.reject(error);
}
);
响应拦截器可以统一处理错误、日志以及业务响应结构。
Promise.reject(error) 表示返回一个失败状态的 Promise,把错误继续传递给调用方。
4. 在业务代码中调用
typescript
// userApi.ts
import { request } from "./request";
interface User {
id: number;
name: string;
}
export async function getUser(id: number): Promise<User> {
const response = await request.get<User>(`/users/${id}`);
return response.data;
}
这样其他组件不需要关心 Axios 的底层配置,只需要调用 getUser()。
七、在 React 中怎么使用 Axios?
这才是你工作中最需要掌握的部分。
假设要开发一个用户信息页面。
typescript
import { useEffect, useState } from "react";
import { getUser } from "./userApi";
interface User {
id: number;
name: string;
}
export default function UserPage() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
let active = true;
async function loadUser() {
try {
const data = await getUser(1001);
if (active) {
setUser(data);
}
} catch {
if (active) {
setError("查询失败");
}
} finally {
if (active) {
setLoading(false);
}
}
}
loadUser();
return () => {
active = false;
};
}, []);
if (loading) {
return <div>加载中...</div>;
}
if (error) {
return <div>{error}</div>;
}
return <div>用户名:{user?.name}</div>;
}
你暂时不需要全部记住,先理解执行流程:
scss
React 组件加载
↓
useEffect 执行
↓
调用 getUser(1001)
↓
Axios 发送 HTTP 请求
↓
Go 后端返回 JSON
↓
setUser(data) 更新状态
↓
React 重新渲染组件
↓
页面显示用户名
这里串联了你前面学过的几个知识点:
async/await:异步等待请求结果。Promise<User>:声明异步返回结果的类型。interface User:描述后端返回的数据结构。useState:保存用户数据。useEffect:处理组件加载后的数据获取。setUser():更新状态,触发页面重新渲染。
八、三个工具的底层关系
容易有一个误解:
AJAX、Fetch、Axios 是三套完全不同的网络通信协议吗?
不是。
它们使用的仍然是 HTTP/HTTPS。
区别主要是前端如何组织和发送请求。
markdown
前端业务代码
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
XMLHttpRequest Fetch Axios
│ │ │
└──────────────┼──────────────┘
▼
浏览器网络能力
│
▼
HTTP
│
▼
Go 后端
Axios 是更高层的 HTTP 客户端封装,在浏览器端通常可以通过 XMLHttpRequest 等适配器实现网络请求,也可以在支持的环境中使用 Fetch 适配器。
因此不能简单理解为 Axios 一定基于 Fetch。
九、开发时到底选哪个?
| 使用场景 | 推荐方案 |
|---|---|
| 学习 HTTP 请求原理 | XMLHttpRequest |
| 原生浏览器项目 | Fetch API |
| 简单接口调用 | Fetch API |
| React + TypeScript 业务项目 | Fetch 或 Axios |
| 需要统一拦截器和请求配置 | Axios |
| 项目已经有 request 封装 | 优先沿用项目现有方案 |
对于你目前工作中的 React 项目,建议先检查有没有这样的文件:
css
src/
├── api/
│ ├── request.ts
│ └── user.ts
├── services/
│ └── task.ts
└── pages/
└── TaskPage.tsx
如果已有统一请求工具,应该优先复用,而不是自己另外引入 Axios。
十、最后总结
你现在需要记住的其实只有三套写法。
1. XMLHttpRequest:回调方式
ini
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/user");
xhr.onload = () => {
console.log(xhr.responseText);
};
xhr.send();
2. Fetch:原生 Promise 方式
ini
const response = await fetch("/api/user");
const data = await response.json();
3. Axios:第三方封装方式
ini
const response = await axios.get("/api/user");
const data = response.data;
一句话总结:
AJAX 是异步请求技术的概念,XMLHttpRequest 是传统浏览器 API,Fetch 是现代原生请求 API,而 Axios 是更方便的第三方 HTTP 客户端。
对 Go 后端开发者而言,真正要掌握的是:如何发请求、如何解析 JSON、如何处理异常,以及如何把返回数据交给 React 组件显示。