Cách Sửa Lỗi 'Blocked by CORS Policy' trong React

intermediate⚛️ React2026-04-15| React (Create React App, Vite, Next.js), Node.js/Express, Python/FastAPI, Go, PHP

Error Message

Access to fetch at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy
#react#cors#api#fetch#proxy

Lỗi Gặp Phải

Khi bạn cố gắng lấy dữ liệu từ một API bên ngoài hoặc một backend chạy trên cổng khác với ứng dụng React của bạn, bạn sẽ thấy lỗi cụ thể này trong console trình duyệt:

Access to fetch at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Lỗi này ngăn ứng dụng của bạn nhận dữ liệu, thường dẫn đến request mạng thất bại dù server thực sự đã xử lý logic đúng.

Nguyên Nhân

CORS (Cross-Origin Resource Sharing) là cơ chế bảo mật được trình duyệt triển khai nhằm ngăn các website độc hại gửi request đến domain khác với domain đang phục vụ trang web. Trong phát triển web hiện đại, ứng dụng React của bạn thường chạy trên http://localhost:3000 trong khi API có thể nằm ở http://localhost:5000 hoặc http://api.example.com. Vì domain hoặc cổng khác nhau, trình duyệt sẽ chặn phản hồi trừ khi server cho phép một cách tường minh.

Các Bước Khắc Phục

Giải Pháp 1: Cấu Hình Phía Server (Cách Được Khuyến Nghị)

Cách mạnh mẽ nhất để giải quyết CORS là cấu hình server backend cho phép request từ origin của ứng dụng React. Bạn cần thêm header Access-Control-Allow-Origin vào phản hồi từ server.

Ví Dụ với Node.js / Express

Cài đặt package cors:

npm install cors

Sau đó, áp dụng nó như middleware trong server.js của bạn:

const express = require('express');
const cors = require('cors');
const app = express();

// Cho phép request từ dev server React của bạn
app.use(cors({
  origin: 'http://localhost:3000'
}));

app.get('/api/data', (req, res) => {
  res.json({ message: 'Success' });
});

app.listen(5000);

Ví Dụ với Python / FastAPI

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

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Giải Pháp 2: Dùng Development Proxy (Phía React)

Nếu bạn không có quyền truy cập vào code backend hoặc muốn giải quyết nhanh khi phát triển local, bạn có thể dùng proxy. Cách này khiến development server của React chuyển tiếp request đến API server, làm trình duyệt nghĩ rằng request xuất phát từ cùng một origin.

Với Create React App (CRA)

Mở package.json và thêm trường proxy ở cuối file:

{
  "name": "my-react-app",
  "version": "0.1.0",
  "dependencies": { ... },
  "proxy": "http://localhost:5000"
}

Sau khi thêm, hãy đổi các lời gọi fetch từ URL tuyệt đối sang đường dẫn tương đối:

// Đổi từ:
fetch('http://localhost:5000/api/users')

// Thành:
fetch('/api/users')

Lưu ý: Bạn phải khởi động lại development server React để thay đổi có hiệu lực.

Với Dự Án Vite

Trong vite.config.ts hoặc vite.config.js, cấu hình server proxy:

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

Giải Pháp 3: Thiết Lập Proxy Middleware Thủ Công

Nếu bạn cần kiểm soát nhiều hơn (ví dụ: proxy đến nhiều backend), hãy dùng http-proxy-middleware.

  • Cài đặt package: npm install http-proxy-middleware
  • Tạo file src/setupProxy.js (Không cần import ở đâu cả, CRA tự động tìm file này).
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};

Các Bước Kiểm Tra

  • Mở ứng dụng React của bạn trong Chrome hoặc Firefox.
  • Nhấn F12 để mở Developer Tools và chuyển sang tab Network.
  • Kích hoạt lời gọi API (ví dụ: tải lại trang hoặc nhấn một nút).
  • Nhấp vào request bị lỗi.
  • Xem mục Response Headers. Nếu cách sửa đã có hiệu lực, bạn sẽ thấy: Access-Control-Allow-Origin: http://localhost:3000 (hoặc *).
  • Kiểm tra Console; lỗi CORS màu đỏ sẽ không còn nữa.

Mẹo Từ Chuyên Gia

  • Tránh Dùng * Trên Production: Mặc dù app.use(cors({ origin: '*' })) tiện cho việc test, nhưng nó không an toàn. Hãy luôn chỉ định đúng domain production của bạn.
  • Kiểm Tra Protocol: http://localhost:3000https://localhost:3000 được coi là hai origin khác nhau. Đảm bảo chúng khớp nhau.
  • Preflight Request: Với các request phức tạp (như request có header tùy chỉnh hoặc phương thức PUT/DELETE), trình duyệt sẽ gửi request OPTIONS trước. Đảm bảo server của bạn xử lý request OPTIONS và trả về đúng CORS header.
  • Cookie và Credentials: Nếu bạn cần gửi cookie hoặc Authorization header, bạn phải đặt credentials: 'include' trong tùy chọn fetch và allow_credentials=True trên server.

Related Error Notes