一,AJAX是什么

AJAX 是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)的缩写。

它的核心作用是:让网页在不重新加载整个页面的情况下,向服务器发送请求并局部更新页面。

比如在百度的搜索框中,我们输一个字下方就会立马弹出一串联想词,但是这并不是直接刷新整个页面,而是AJAX在后台随着输入,不断向服务器请求匹配,局部刷新下面那一串联想词。

AJAX实际是以下几种技术的组合:

  1. HTML / CSS: 负责网页的结构和样式(长成什么样)。
  2. DOM(文档对象模型): 负责动态显示和与数据交互(怎么局部改变网页内容)。
  3. Fetch API 或 XMLHttpRequest 对象: (最核心) 浏览器自带的幕后英雄,负责在后台悄悄与服务器交换数据。
  4. 数据格式(JSON / XML): 服务器返回的数据格式。虽然 AJAX 名字里有 XML,但因为 XML 太繁琐,现在行业内 99% 都在使用更轻量、更好读的 JSON 格式。

工作流程:

[ 网页触发事件 ] (如点击按钮)
      │
      ▼
[ 创建请求并发送 ] (JavaScript 在后台向服务器发送请求)
      │
      ▼
[ 服务器处理 ] (服务器收到请求,提取数据,只返回需要的数据,如 JSON)
      │
      ▼
[ 局部更新网页 ] (JavaScript 收到数据,更新网页的某一部分)

二,使用 Axios 来实现 AJAX 请求

Axios 是一个基于 Promise 的 HTTP 客户端,主要用于在浏览器和 Node.js 环境中发送异步 HTTP 请求(如 GET、POST、PUT、DELETE 等)。

简单来说,它是一个封装好的 JavaScript 库,让你能够更方便地与后端 API 进行通信。

Axios 是 AJAX 技术的一种具体实现工具。

1.和fetch的区别

fetch和Axios一样,同样是实现AJAX的一种工具。

fetch 是浏览器自带的“基本款”Promise 式请求 API,Axios 是在它(或 XMLHttpRequest)之上封装的“增强版”库,提供了更多便捷功能。 两者都能实现 AJAX 请求,只是 Axios 用起来更省心。

2.下载Axios

Axios 是一个第三方库,使用前需要先把它“拿”到你的项目里。

  1. 方式一:在 HTML 中直接使用 CDN(最快速上手)

    html
    <!-- 在 body 底部或 head 中引入 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    

    引入后,全局就有了 axios 对象。
    或者直接下载这个文件,在本地导入,更快捷。

  2. 方式二:使用 npm(用于 Node.js 或现代前端工程)

    npm install axios
    

    然后在代码中:

    const axios = require('axios');   // Node.js (CommonJS)
    // 或
    import axios from 'axios';         // ES module (Vue/React)
    

3.使用Axios

下载后,项目中就会多一个axios对象,在浏览器中就是window.axios。

我们本质上是用Axios的方法来‘发请求’。

每个方法对应一种HTTP请求动作。

他们的返回值就是Promise对象,这个对象上有.then()等方法,用于处理拿到数据之后该干什么。

通常像下面这样写:

前端Axios代码:

import axios from 'axios';

// 1. 设置全局的 baseURL(通常放在项目的入口文件,如 main.js 或 index.js 里)
axios.defaults.baseURL = 'http://127.0.0.1:8000'; 

// 2. 设置全局的超时时间,单位是【毫秒】(1秒 = 1000毫秒)
axios.defaults.timeout = 5000; // 代表 5 秒内服务器没响应就中断并报错

// 3. 之后发请求,直接写相对路径即可
axios.get('/get')  // Axios 会自动拼接成 http://127.0.0.1:8000/get
  .then(res => console.log(res.data));

axios.post('/items', { name: '商品' }) // 自动拼接成 http://127.0.0.1:8000/items
  .then(res => console.log(res.data));

后端FastAPI代码:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 💡 避坑:只要是前后端分离(哪怕都在本地,只要端口不同),就必须加下面这段 CORS 配置!
# 这里配置的是跨域资源共享中间件,用于解决浏览器中AJAX请求的跨域限制问题。
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"], # 在生产环境建议换成你前端的实际域名/端口
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/get")
def get_data():
    return {"message": "成功访问 /get 接口"}

为什么需要那个中间件呢?
浏览器基于同源策略,默认禁止网页向不同域名/端口发送 AJAX 请求。例如:
前端运行在 http://localhost:3000
后端 API 运行在 http://localhost:8000
没有 CORS 配置时,浏览器会拦截请求并报错。加上这段代码后,后端会告诉浏览器“允许跨域访问”,从而请求可以正常进行。

4.Axios 常用方法速查表

Axios 方法 对应的 HTTP 动作 典型应用场景 第二个参数填什么? 第三个参数填什么? 对应的 FastAPI 接收注解
axios.get(url, config) GET 获取数据 / 查询 config 配置项(如 params 查询参数) def get_data(id: int) (Query 或 Path)
axios.post(url, data, config) POST 提交数据 / 新建资源 data(要发送的 JSON 对象或 Form) config 配置项(可省略) def create(item: BaseModel) (Body)
axios.put(url, data, config) PUT 更新数据(完整替换) data(更新后的完整对象) config 配置项(可省略) def update(item: BaseModel) (Body)
axios.patch(url, data, config) PATCH 局部修改数据(只改部分字段) data(需要修改的局部字段) config 配置项(可省略) def patch(item: PartialModel) (Body)
axios.delete(url, config) DELETE 删除数据 config 配置项(通常把 ID 拼在 URL 里) def delete_data(id: int) (Path)

还有以下写法。

// 这种写法下,所有配置都在同一个对象里,不用去记参数的第几位是什么
axios({
    method: 'post',               // 请求方式:get, post, put, delete 等
    url: '/user/12345',           // 相对路径或绝对路径
    params: { id: 'query_id' },   // 无论是 POST 还是 GET,Query 参数都写在这里
    data: { firstName: 'Fred' },  // 只有 POST/PUT/PATCH 的 Body 数据写在这里
    timeout: 3000                 // 超时时间
});

5.Promise常用方法速查表

  1. 实例方法(非静态方法 / 原型方法)
    这类方法必须用在 Promise 实例对象后面,用来链式处理异步操作的最终结果(成功、失败或结束)。

    实例方法 触发时机 / 作用 接收的参数 返回值 示例代码
    .then() 当 Promise 变为 成功(Fulfilled) 时触发 一个回调函数,函数的参数是成功返回的数据 返回一个新的 Promise(可以继续链式调用) axios.get('/user').then(res => { console.log(res) })
    .catch() 当 Promise 变为 失败(Rejected) 或代码报错时触发 一个回调函数,函数的参数是错误对象(Error) 返回一个新的 Promise axios.get('/user').catch(err => { console.error(err) })
    .finally() 无论成功还是失败,只要异步操作结束了就一定会触发 一个无参数的回调函数 返回当前的 Promise showLoading(); axios.get('/user').finally(() => { hideLoading() })
  2. 静态方法(类方法)

    这类方法不需要 new 实例,直接通过大写的 Promise 关键字调用,通常用于并发处理多个异步操作(比如同时发多个 Axios 请求)。

    静态方法 核心逻辑(什么时候算成功/失败) 常用应用场景 示例与返回值
    Promise.all(iterable) 全胜才胜,一败俱败

    所有 Promise 都成功才算成功,返回所有结果的数组;只要有一个失败,就立刻整体宣告失败。
    页面加载时,需要同时获取“用户信息”和“菜单列表”,都拿到了再渲染页面。 Promise.all([req1, req2]).then(([res1, res2]) => { ... })
    Promise.allSettled(iterable) 有始有终,全数等齐

    不管成功还是失败,必须等所有异步都执行完,返回一个包含每个任务状态和结果的数组。
    批量发送邮件或下载文件,最后需要统计“哪些成功了,哪些失败了”。 Promise.allSettled([req1, req2]).then(results => { ... })
    Promise.race(iterable) 谁快听谁,不论好坏

    谁的速度最快(不管是成功还是失败),就以谁的结果作为最终结果。
    给某个异步操作设置超时限制(让你的请求和定时器赛跑)。 Promise.race([fetchData(), timeout(3000)])
    Promise.any(iterable) 得一胜足矣,全败才败

    只要有一个成功就立即算成功,返回那个成功的结果;只有全部都失败,才会宣告失败。
    从多个不同的镜像服务器/CDN 获取同一个资源,谁先成功返回就用谁的。 Promise.any([cdn1, cdn2, cdn3]).then(fastestData => { ... })
    Promise.resolve(value) 直接创建一个已经是成功状态的 Promise 对象。 快速将一个普通数据或第三方数据包装成标准 Promise。 const p = Promise.resolve('数据');
    Promise.reject(reason) 直接创建一个已经是失败状态的 Promise 对象。 在测试或自定义逻辑中,手动抛出一个异步错误。 const p = Promise.reject(new Error('拒绝访问'));

6.完整示例

  1. 后端fastapi代码

    from fastapi import FastAPI, HTTPException, Form
    from fastapi.middleware.cors import CORSMiddleware
    from pydantic import BaseModel
    from typing import Optional
    import asyncio
    
    app = FastAPI()
    
    # 允许跨域(本地开发测试必加)
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    
    # 模拟数据库
    fake_db = {
        1: {"name": "iPhone 17 Pro", "price": 8999.0, "status": "active"},
        2: {"name": "MacBook Pro M5", "price": 14999.0, "status": "active"}
    }
    
    # 1. 对应 Axios.get + Path 参数
    @app.get("/items/{item_id}")
    async def get_item(item_id: int):
        if item_id not in fake_db:
            raise HTTPException(status_code=404, detail="商品不存在")
        return fake_db[item_id]
    
    # 2. 对应 Axios.get + Query 参数
    @app.get("/items")
    async def list_items(status: str = "active", limit: int = 10):
        # 模拟快速响应
        return [item for item in fake_db.values() if item["status"] == status][:limit]
    
    # 模拟一个特别慢的第三方数据源(用于测试比赛/超时)
    @app.get("/slow-backup-source")
    async def slow_source():
        await asyncio.sleep(4)  # 故意睡 4 秒
        return {"source": "备份服务器", "data": "一些商品元数据"}
    
    # 3. 对应 Axios.post + JSON 请求体
    class ItemModel(BaseModel):
        name: str
        price: float
        status: Optional[str] = "active"
    
    @app.post("/items")
    async def create_item(item: ItemModel):
        new_id = max(fake_db.keys()) + 1
        fake_db[new_id] = item.model_dump()
        return {"id": new_id, **fake_db[new_id]}
    
    # 4. 对应 Axios.put + 完整修改
    @app.put("/items/{item_id}")
    async def update_item(item_id: int, item: ItemModel):
        if item_id not in fake_db:
            raise HTTPException(status_code=404, detail="修改失败,商品不存在")
        fake_db[item_id] = item.model_dump()
        return {"message": "更新成功", "data": fake_db[item_id]}
    
    # 5. 对应 Axios.delete + 删除
    @app.delete("/items/{item_id}")
    async def delete_item(item_id: int):
        if item_id in fake_db:
            del fake_db[item_id]
            return {"message": f"成功删除商品 {item_id}"}
        raise HTTPException(status_code=404, detail="商品不存在")
    
  2. 前端js代码

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Axios & Promise 综合实战演练</title>
        <!-- 引入 Axios CDN -->
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
        <style>
            body {
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                background-color: #f5f7fa;
                color: #333;
                padding: 40px;
                max-width: 900px;
                margin: 0 auto;
            }
            h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; }
            .card {
                background: white;
                padding: 24px;
                border-radius: 12px;
                box-shadow: 0 4px 6px rgba(0,0,0,0.05);
                margin-bottom: 20px;
            }
            h3 { margin-top: 0; color: #34495e; border-left: 4px solid #3498db; padding-left: 10px; }
            .btn-group { display: flex; gap: 12px; margin-top: 15px; flex-wrap: wrap; }
            button {
                background-color: #3498db;
                color: white;
                border: none;
                padding: 10px 20px;
                border-radius: 6px;
                cursor: pointer;
                font-weight: bold;
                transition: background 0.2s;
            }
            button:hover { background-color: #2980b9; }
            button.secondary { background-color: #2ecc71; }
            button.secondary:hover { background-color: #27ae60; }
            button.warning { background-color: #e67e22; }
            button.warning:hover { background-color: #d35400; }
            
            #log-container {
                background-color: #2c3e50;
                color: #2ecc71;
                padding: 15px;
                border-radius: 8px;
                font-family: "Courier New", Courier, monospace;
                height: 300px;
                overflow-y: auto;
                white-space: pre-wrap;
                box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
            }
            .status-bar {
                display: inline-block;
                padding: 4px 8px;
                border-radius: 4px;
                font-size: 12px;
                font-weight: bold;
                background-color: #bdc3c7;
                color: white;
                margin-bottom: 15px;
            }
            .loading { background-color: #f1c40f; color: #333; }
            .idle { background-color: #95a5a6; }
        </style>
    </head>
    <body>
    
        <h1>Axios & Promise 综合实战大看板</h1>
    
        <!-- 状态指示器 -->
        <div id="global-status" class="status-bar idle">当前状态: 空闲</div>
    
        <!-- 实验控制面板 -->
        <div class="card">
            <h3>控制台与操作面板</h3>
            <p>请先启动 FastAPI 后端,然后点击下方按钮观察请求流。同时请**打开浏览器控制台 (F12)** 查看完整的网络对象数据。</p>
            
            <div class="btn-group">
                <button onclick="manageProductFlow()">1. 运行商品增删改链条 (实例方法)</button>
                <button class="secondary" onclick="initDashboard()">2. 模拟大屏初始化 (并发方法)</button>
                <button class="warning" onclick="loadBackupDataWithRace()">3. 触发数据竞速与降级 (高级方法)</button>
                <button style="background-color: #95a5a6;" onclick="clearLogs()">清空日志</button>
            </div>
        </div>
    
        <!-- 实时可视日志 -->
        <div class="card">
            <h3>实时操作日志 (页面输出)</h3>
            <div id="log-container">等待操作...</div>
        </div>
    
        <script>
            // ==================== 1. AXIOS 全局配置 ====================
            axios.defaults.baseURL = 'http://127.0.0.1:8000';
            axios.defaults.timeout = 5000; // 全局超时 5 秒
    
            // UI 日志辅助函数
            const logBox = document.getElementById('log-container');
            const statusBar = document.getElementById('global-status');
    
            function printLog(message, type = 'info') {
                const time = new Date().toLocaleTimeString();
                let prefix = `[${time}] `;
                if (type === 'error') prefix += '❌ ';
                if (type === 'success') prefix += '✅ ';
                
                if (logBox.innerText === '等待操作...') {
                    logBox.innerText = prefix + message + '\n';
                } else {
                    logBox.innerText += prefix + message + '\n';
                }
                logBox.scrollTop = logBox.scrollHeight; // 滚动条自动滚到底
            }
    
            function setStatus(statusText, isLoading = false) {
                statusBar.innerText = `当前状态: ${statusText}`;
                if (isLoading) {
                    statusBar.className = "status-bar loading";
                } else {
                    statusBar.className = "status-bar idle";
                }
            }
    
            function clearLogs() {
                logBox.innerText = '等待操作...';
            }
    
    
            // ==================== 2. 核心核心业务逻辑 ====================
    
            // 场景 A:发布商品并连续修改、删除
            // 涵盖:axios.post, axios.put, axios.delete, .then(), .catch(), .finally()
            function manageProductFlow() {
                printLog("=== 启动场景 1:商品流管理 ===");
                setStatus("正在提交数据...", true);
    
                // [Axios.post]: 新增一个商品 (接收 JSON 请求体)
                axios.post('/items', { name: 'iPad Pro OLED', price: 7999.0 })
                    .then(response => {
                        // [Promise 实例方法 .then]
                        const newId = response.data.id;
                        printLog(`新增成功!FastAPI 返回新商品ID: ${newId}`, 'success');
                        console.log("新增响应详情:", response);
                        
                        // 链式调用 [Axios.put]: 紧接着修改这个商品的价格
                        printLog(`继续链式调用:正在修改商品 ${newId} 的价格...`);
                        return axios.put(`/items/${newId}`, { name: 'iPad Pro OLED', price: 7499.0 }); 
                    })
                    .then(putResponse => {
                        printLog(`修改价格成功!最新价格: ${putResponse.data.data.price}`, 'success');
                        console.log("修改响应详情:", putResponse);
                        
                        // 链式调用 [Axios.delete]: 删掉数据库里的商品 1
                        printLog("继续链式调用:正在尝试删除商品 ID: 1 ...");
                        return axios.delete('/items/1'); 
                    })
                    .then(deleteResponse => {
                        printLog(`删除操作完成:${deleteResponse.data.message}`, 'success');
                        console.log("删除响应详情:", deleteResponse);
                    })
                    .catch(error => {
                        // [Promise 实例方法 .catch]: 统一捕获链条中任何一步发生的错误
                        printLog(`流程中某一步出错: ${error.message}`, 'error');
                        if (error.response) {
                            console.error("后端返回的错误状态码:", error.response.status);
                        }
                    })
                    .finally(() => {
                        // [Promise 实例方法 .finally]
                        setStatus("空闲");
                        printLog("场景 1 流程结束。");
                    });
            }
    
    
            // 场景 B:大屏数据并发初始化
            // 涵盖:axios.get (Path参数), axios.get (Query参数), Promise.all, Promise.allSettled
            async function initDashboard() {
                printLog("=== 启动场景 2:大屏并发初始化 ===");
                setStatus("正在并发请求多源数据...", true);
    
                // 准备 3 个不同的 Axios 请求任务(注意:此时请求已发出,它们在并行执行)
                const req1 = axios.get('/items/2');                     // 成功 (Path参数)
                const req2 = axios.get('/items', { params: { limit: 5 } }); // 成功 (Query参数)
                const req3 = axios.get('/items/999');                   // 必定失败:FastAPI 里没 999 这个商品,会报 404
    
                // ---- 演示 Promise.all (全胜才胜) ----
                try {
                    printLog("执行 Promise.all 中(打包任务 1 和任务 2,预期全部成功)...");
                    const [res1, res2] = await Promise.all([req1, req2]);
                    printLog(`【Promise.all 成功】商品2名字: ${res1.data.name},列表商品数: ${res2.data.length}`, 'success');
                } catch (err) {
                    printLog(`【Promise.all 失败】报错了: ${err.message}`, 'error');
                }
    
                // ---- 演示 Promise.allSettled (全部等齐,不管输赢) ----
                printLog("执行 Promise.allSettled 中(打包任务 1、2 以及必然失败的任务 3)...");
                const results = await Promise.allSettled([req1, req2, req3]);
                
                printLog("【Promise.allSettled 检查各通道结果】:");
                results.forEach((result, index) => {
                    if (result.status === 'fulfilled') {
                        printLog(` └─ 任务 ${index + 1} 成功,数据状态码: ${result.value.status}`, 'success');
                    } else {
                        // 任务 3 会走到这里
                        printLog(` └─ 任务 ${index + 1} 失败,原因: ${result.reason.message}`, 'error');
                    }
                });
    
                setStatus("空闲");
                printLog("场景 2 流程结束。");
            }
    
    
            // 场景 C:高级竞速与本地降级
            // 涵盖:Promise.race, Promise.any, Promise.resolve, Promise.reject
            async function loadBackupDataWithRace() {
                printLog("=== 启动场景 3:数据竞速与降级 ===");
                setStatus("正在执行竞速逻辑...", true);
    
                // 1. 创建一个自定义的前端 3 秒超时拒绝任务,用来和后端的慢接口“赛跑”
                const timeoutPromise = new Promise((_, reject) => {
                    setTimeout(() => reject(new Error("前端自定义控制:服务器响应太慢,已被强行中断!")), 3000);
                });
    
                // ---- 演示 Promise.race (谁快听谁) ----
                try {
                    printLog("【Promise.race】让【4秒才响应的后端接口】与【3秒定时器】赛跑...");
                    // 后端慢接口需要 4 秒,定时器只需要 3 秒。定时器跑赢并触发了错误(reject),所以整体直接进 catch
                    await Promise.race([
                        axios.get('/slow-backup-source'), 
                        timeoutPromise
                    ]);
                } catch (raceError) {
                    printLog(`【Promise.race 赛跑结果】: ${raceError.message}`, 'error');
                }
    
                // ---- 演示 Promise.any (得一胜足矣) 与 静态快速创建 ----
                printLog("【Promise.any】模拟多服务器并发容错(包含死服务器、好服务器、本地缓存)...");
                
                const fastFailure = Promise.reject(new Error("一号镜像服务器发生致命闪退")); // [Promise.reject] 瞬间失败
                const slowSuccess = axios.get('/items/2'); // 正常请求,需要几十毫秒
                const localFallback = Promise.resolve({ data: { name: "本地离线降级商品", price: -1 } }); // [Promise.resolve] 瞬间成功
    
                try {
                    // Promise.any 只要有一个成功就行。
                    // 此时 fastFailure 瞬间失败被忽略,slowSuccess 和 localFallback 都是成功的。
                    // 因为 localFallback 是本地同步代码瞬间完成,它最快,所以 any 最终会采纳 localFallback 的数据。
                    const winnerResponse = await Promise.any([fastFailure, slowSuccess, localFallback]);
                    printLog(`【Promise.any 胜出者数据】: ${winnerResponse.data.name}`, 'success');
                    console.log("Promise.any 拿到的完整对象: ", winnerResponse);
                } catch (anyError) {
                    printLog("只有全部都失败了才会进到这里", 'error');
                }
    
                setStatus("空闲");
                printLog("场景 3 流程结束。");
            }
        </script>
    </body>
    </html>
    

三,关于进阶的内容

除了请求方法,Axios 之所以能成为企业级开发的事实标准,是因为它围绕网络请求的生命周期、安全和工程化提供了非常完备的解决方案。

1.拦截器(Interceptors)

拦截器就像是请求和响应在路上的“安全检查站”。你可以在它们到达 FastAPI 或前端组件之前,统一对它们进行修改或拦截。

  • 请求拦截器:在请求发出去之前执行。通常用来统一自动添加 Token。
  • 响应拦截器:在数据回到 .then() 之前执行。通常用来统一剥离外壳数据或统一处理报错。
// 创建实例
const api = axios.create({ baseURL: 'http://127.0.0.1:8000' });

// 1. 请求拦截器
api.interceptors.request.use(config => {
    const token = localStorage.getItem('user_token');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
}, error => {
    return Promise.reject(error);
});

// 2. 响应拦截器
api.interceptors.response.use(response => {
    return response.data;
}, error => {
    if (error.response && error.response.status === 401) {
        alert("登录过期,请重新登录!");
        window.location.href = '/login';
    }
    return Promise.reject(error);
});

2. 取消请求(CancelToken / AbortController)

在某些高频交互的场景下,前一个请求还没结束,用户又触发了新请求,为了节约带宽或防止数据错乱,需要取消上一次未完成的请求。

💡 现代推荐:使用浏览器原生的 AbortController(取代 Axios 自带的 CancelToken)。

典型场景:输入框搜索联想

let controller = null;

function searchProducts(keyword) {
    if (controller) {
        controller.abort();
    }
    controller = new AbortController();

    axios.get('/search', {
        params: { q: keyword },
        signal: controller.signal
    })
    .then(res => console.log("搜索结果:", res.data))
    .catch(err => {
        if (axios.isCancel(err)) {
            console.log("成功取消了上一次的高频重复请求");
        } else {
            console.error("真正的请求报错:", err);
        }
    });
}

3. 防范 XSS / CSRF 安全攻击

Axios 内置了对 CSRF(跨站请求伪造)的防御机制。如果后端在 Cookie 中写入了动态 Token(如 XSRF-TOKEN),Axios 会自动读取并添加到请求头 X-XSRF-TOKEN 中。

只需全局配置:

axios.defaults.xsrfCookieName = 'XSRF-TOKEN';   // 读取 Cookie 的名字
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN'; // 写入 Header 的名字

4. 上传与下载的进度监听(Progress Events)

当上传大文件或下载超大 Excel 时,可监听进度以提升用户体验。

const formData = new FormData();
formData.append('file', fileObject);

axios.post('/upload', formData, {
    onUploadProgress: (progressEvent) => {
        const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
        console.log(`上传进度:${percent}%`);
        // 更新进度条组件
    }
})
.then(res => console.log("上传成功"));

5. 错误对象的层级划分(AxiosError)

Axios 抛出的错误包含丰富的网络上下文,便于定位问题。

axios.get('/data')
    .catch(error => {
        if (error.response) {
            // 后端返回了非 2xx 状态码(如 404, 500, 422)
            console.log("状态码:", error.response.status);
            console.log("报错详情:", error.response.data);
        } else if (error.request) {
            // 请求发出但未收到响应(超时、断网、服务未启动)
            console.log("无响应:", error.request);
        } else {
            // 请求配置阶段出错(极少见)
            console.log("请求错误:", error.message);
        }
    });
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐