<tech-stash />
HomeBlogSnippetsAbout
Đăng nhập
Quay lại Blog
APIAxiosDesign PatternReact

Axios Interceptor: Hiểu sâu kiến trúc Middleware và ứng dụng thực tế trong React

29 tháng 4, 20264 phút đọc

Khi mới làm quen với việc gọi API trong React, chúng ta thường viết các đoạn code gắn Token hoặc xử lý lỗi 401 trực tiếp vào từng hàm fetch hoặc axios.get(). Cách làm này hoạt động được, nhưng khi hệ thống phình to lên hàng trăm API, nó sẽ lập tức phá vỡ nguyên tắc DRY (Don't Repeat Yourself) và khiến code base trở nên cực kỳ khó bảo trì.

Để giải quyết bài toán này ở tầm nhìn kiến trúc, chúng ta cần một cơ chế can thiệp ở cấp độ toàn cục (global). Đó chính là lúc Interceptor Pattern lên tiếng.

1. Bản chất của Interceptor trong Kỹ thuật phần mềm

Trong Kỹ thuật phần mềm (Software Engineering), Interceptor là một mẫu thiết kế (Design Pattern) thuộc nhóm cấu trúc. Nó cho phép một ứng dụng chèn thêm các bước xử lý vào một luồng thực thi (pipeline) có sẵn mà không cần phải thay đổi mã nguồn cốt lõi của luồng đó.

Khái niệm này có sự tương đồng rất lớn với Middleware trong các backend framework như Express.js hay NestJS.

Interceptor sinh ra để giải quyết một khái niệm cốt lõi: Cross-cutting Concerns (Các mối quan tâm cắt ngang). Đây là những logic không thuộc về nghiệp vụ chính (Business Logic) của một hàm, nhưng lại bắt buộc phải có mặt ở khắp mọi nơi. Điển hình nhất là:

  • Authentication & Authorization: Xác thực người dùng bằng Token.

  • Logging: Ghi nhận thời gian và thông số của mọi request.

  • Error Handling: Bắt và xử lý các lỗi hệ thống (ví dụ: 500 Internal Server Error, 401 Unauthorized).

  • Data Transformation: Mã hóa/Giải mã payload trước khi truyền tải.

Thay vì phân tán các logic này, Interceptor gom chúng lại và đặt tại một "trạm kiểm soát" duy nhất.

2. Vòng đời của một Request và cơ chế Promise Chaining trong Axios

Dưới mui xe (under the hood), thư viện axios quản lý luồng dữ liệu dựa trên Promise Chaining (Chuỗi Promise). Khi bạn khai báo một Interceptor, thực chất bạn đang đẩy thêm các hàm resolve và reject vào mảng Promise của Axios.

Luồng đi của một API Call thông qua Axios diễn ra như sau:

  1. Request Interceptors: Khi bạn gọi axios.get(), request chưa bay ra network ngay. Nó sẽ chạy qua tất cả các hàm Request Interceptor mà bạn đã đăng ký (theo thứ tự LIFO hoặc FIFO tùy cấu hình). Mỗi interceptor nhận vào config object, chỉnh sửa nó, và bắt buộc phải return lại config đó để truyền cho mắt xích tiếp theo.

  2. Dispatch Request: Axios thực hiện gửi HTTP Request thực tế lên Server và đợi kết quả.

  3. Response Interceptors: Khi Server trả về Response, dữ liệu lại đi qua các Response Interceptor. Tại đây, bạn có thể kiểm tra HTTP Status Code. Nếu thành công (2xx), luồng đi vào nhánh Fulfilled. Nếu thất bại, luồng rẽ sang nhánh Rejected.

  4. Hàm gọi API của bạn: Cuối cùng, dữ liệu (hoặc lỗi) mới được trả về hàm .then() hoặc .catch() trong component của bạn.

3. Thực hành: Cấu hình Request Interceptor

Ứng dụng lớn nhất của Request Interceptor là tự động gắn Authorization Header. Code thực thi rất đơn giản, nhưng bạn cần nhớ quy tắc nền tảng: Luôn phải return lại config. Nếu không, chuỗi Promise sẽ bị đứt gãy và request sẽ bị treo.

JavaScript

code.ts
import axios from 'axios';

// 1. Khởi tạo một instance riêng biệt
const apiClient = axios.create({
  baseURL: 'https://api.domaincuaban.com/v1',
  timeout: 10000, 
});

// 2. Thiết lập Request Interceptor
apiClient.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('accessToken');
    
    // Can thiệp vào gói tin: Gắn thêm Header trước khi gửi
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    // Quan trọng: Trả lại config để Axios đẩy request đi tiếp
    return config; 
  },
  (error) => {
    // Bắt lỗi nếu quá trình setup config gặp sự cố
    return Promise.reject(error);
  }
);

4. Thực hành: Cấu hình Response Interceptor

Response Interceptor là nơi lý tưởng để làm 2 việc: Bóc tách dữ liệu rườm rà và xử lý lỗi tập trung.

JavaScript

code.ts
apiClient.interceptors.response.use(
  (response) => {
    // Nhánh Fulfilled: Status code 2xx
    // Trích xuất trực tiếp phần 'data' để Component không phải gọi response.data.data
    return response.data;
  },
  (error) => {
    // Nhánh Rejected: Status code nằm ngoài 2xx
    
    if (error.response) {
      // Ví dụ: Xử lý tập trung lỗi 401 (Hết phiên đăng nhập)
      if (error.response.status === 401) {
        console.warn("Token expired. Redirecting to login...");
        localStorage.removeItem('accessToken');
        window.location.href = '/login';
      }
      
      // Xử lý các lỗi HTTP khác (403, 500...) tại đây
    }

    // Đẩy lỗi về cuối chuỗi Promise để Component có thể catch() nếu cần
    return Promise.reject(error);
  }
);

export default apiClient;

5. Lời kết

Việc sử dụng Axios Interceptor không đơn thuần là việc học cách dùng một API của thư viện, mà là việc thực hành tư duy kiến trúc. Bằng cách tách biệt phần xử lý mạng (Network Logic) và logic xác thực (Auth Logic) ra khỏi logic hiển thị của React (UI Logic), bạn đang tạo ra một code base tuân thủ nguyên tắc Single Responsibility (Đơn trách nhiệm), giúp ứng dụng dễ dàng mở rộng và bảo trì trong tương lai.

On this page
  • 1. Bản chất của Interceptor trong Kỹ thuật phần mềm
  • 2. Vòng đời của một Request và cơ chế Promise Chaining trong Axios
  • 3. Thực hành: Cấu hình Request Interceptor
  • 4. Thực hành: Cấu hình Response Interceptor
  • 5. Lời kết
© 2026 Thai Bao — Tech Stash
BlogSnippetsAboutRSS