上一篇介紹了 Axios 的基本概念,這篇我們來實際練習如何使用 Axios 來進行 HTTP 請求。

建立 Axios 實例

我們可以建立一個 Axios 實例來設定共用的配置:

const api = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com',
    timeout: 5000,
    headers: {
        'Content-Type': 'application/json'
    }
});

實作範例:用戶管理系統

讓我們建立一個簡單的用戶管理系統來練習各種 HTTP 方法。

HTML 結構

<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Axios 實作練習</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
    <div id="app">
        <h1>用戶管理系統</h1>
        
        <!-- 用戶列表 -->
        <div id="users"></div>
        
        <!-- 新增用戶表單 -->
        <form id="userForm">
            <input type="text" id="name" placeholder="姓名" required>
            <input type="email" id="email" placeholder="Email" required>
            <button type="submit">新增用戶</button>
        </form>
    </div>
</body>
</html>

JavaScript 實作

// 建立 Axios 實例
const api = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com',
    timeout: 5000
});

// DOM 元素
const usersDiv = document.getElementById('users');
const userForm = document.getElementById('userForm');

// 取得所有用戶
async function fetchUsers() {
    try {
        const response = await api.get('/users');
        displayUsers(response.data);
    } catch (error) {
        console.error('取得用戶資料失敗:', error);
        alert('取得用戶資料失敗');
    }
}

// 顯示用戶列表
function displayUsers(users) {
    usersDiv.innerHTML = users.map(user => `
        <div class="user-card">
            <h3>${user.name}</h3>
            <p>Email: ${user.email}</p>
            <p>電話: ${user.phone}</p>
            <button onclick="editUser(${user.id})">編輯</button>
            <button onclick="deleteUser(${user.id})">刪除</button>
        </div>
    `).join('');
}

// 新增用戶
async function createUser(userData) {
    try {
        const response = await api.post('/users', userData);
        console.log('用戶新增成功:', response.data);
        alert('用戶新增成功');
        fetchUsers(); // 重新載入用戶列表
    } catch (error) {
        console.error('新增用戶失敗:', error);
        alert('新增用戶失敗');
    }
}

// 更新用戶
async function updateUser(id, userData) {
    try {
        const response = await api.put(`/users/${id}`, userData);
        console.log('用戶更新成功:', response.data);
        alert('用戶更新成功');
        fetchUsers(); // 重新載入用戶列表
    } catch (error) {
        console.error('更新用戶失敗:', error);
        alert('更新用戶失敗');
    }
}

// 刪除用戶
async function deleteUser(id) {
    if (!confirm('確定要刪除這個用戶嗎?')) return;
    
    try {
        await api.delete(`/users/${id}`);
        console.log('用戶刪除成功');
        alert('用戶刪除成功');
        fetchUsers(); // 重新載入用戶列表
    } catch (error) {
        console.error('刪除用戶失敗:', error);
        alert('刪除用戶失敗');
    }
}

// 表單提交事件
userForm.addEventListener('submit', (e) => {
    e.preventDefault();
    
    const name = document.getElementById('name').value;
    const email = document.getElementById('email').value;
    
    createUser({ name, email });
    
    // 清空表單
    userForm.reset();
});

// 頁面載入時取得用戶資料
document.addEventListener('DOMContentLoaded', fetchUsers);

進階功能

請求攔截器

// 請求攔截器 - 在每個請求發送前執行
api.interceptors.request.use(
    config => {
        console.log('發送請求:', config);
        // 可以在這裡添加認證 token
        // config.headers.Authorization = `Bearer ${token}`;
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);

回應攔截器

// 回應攔截器 - 在每個回應接收後執行
api.interceptors.response.use(
    response => {
        console.log('收到回應:', response);
        return response;
    },
    error => {
        if (error.response?.status === 401) {
            // 處理認證失敗
            alert('認證失敗,請重新登入');
        }
        return Promise.reject(error);
    }
);

取消請求

let cancelToken;

async function fetchUsersWithCancel() {
    // 如果之前有請求正在進行,先取消它
    if (cancelToken) {
        cancelToken.cancel('取消之前的請求');
    }
    
    // 建立新的取消令牌
    cancelToken = axios.CancelToken.source();
    
    try {
        const response = await api.get('/users', {
            cancelToken: cancelToken.token
        });
        displayUsers(response.data);
    } catch (error) {
        if (axios.isCancel(error)) {
            console.log('請求已取消');
        } else {
            console.error('請求失敗:', error);
        }
    }
}

錯誤處理最佳實務

async function handleRequest() {
    try {
        const response = await api.get('/users');
        return response.data;
    } catch (error) {
        if (error.response) {
            // 伺服器回應了錯誤狀態碼
            console.error('回應錯誤:', error.response.status, error.response.data);
        } else if (error.request) {
            // 請求已發出但沒有收到回應
            console.error('網路錯誤:', error.request);
        } else {
            // 其他錯誤
            console.error('錯誤:', error.message);
        }
        throw error;
    }
}