Tóm tắt: Cách xử lý trong 60 giây
Để khắc phục lỗi này, bạn cần yêu cầu máy chủ backend tin tưởng frontend của mình. Điều này được thực hiện bằng cách thêm header Access-Control-Allow-Origin vào các phản hồi API. Trong môi trường phát triển, bạn có thể sử dụng ký tự đại diện (wildcard) để cho phép tất cả mọi thứ:
Access-Control-Allow-Origin: *
Đối với môi trường production, bạn nên chỉ định cụ thể hơn. Thay thế * bằng tên miền thực tế của bạn, ví dụ như https://app.yourdomain.com. Lưu ý quan trọng: việc sửa lỗi này phải được thực hiện trên máy chủ hoặc API gateway của bạn, chứ không phải trong mã nguồn frontend.
Tại sao trình duyệt lại chặn bạn?
Các trình duyệt sử dụng một cơ chế bảo mật gọi là Same-Origin Policy (SOP). Nó ngăn chặn một trang web độc hại thực hiện các yêu cầu tới API riêng tư của bạn. Khi ứng dụng React của bạn tại localhost:3000 cố gắng lấy dữ liệu từ api.domain.com, trình duyệt sẽ nhận thấy các tên miền không khớp nhau. Nó sẽ ngay lập tức tìm kiếm một "giấy phép" từ máy chủ.
Nếu máy chủ không trả lại quyền đó thông qua header Access-Control-Allow-Origin, trình duyệt sẽ hủy yêu cầu. Bạn sẽ thấy dòng chữ đỏ quen thuộc này trong console:
Access to fetch at 'http://api.domain.com' from origin 'http://localhost:3000' has been blocked by CORS policy.
Cách khắc phục CORS trên Backend của bạn
1. Node.js (Express)
Middleware cors là giải pháp tiêu chuẩn cho các ứng dụng Express. Nó sẽ xử lý các tác vụ phức tạp thay bạn.
// Cài đặt: npm install cors
const express = require('express');
const cors = require('cors');
const app = express();
// Tùy chọn A: Cho phép tất cả (Tốt để kiểm tra nhanh)
app.use(cors());
// Tùy chọn B: Thiết lập bảo mật (Khuyên dùng cho production)
const corsOptions = {
origin: 'https://my-cool-app.com',
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
2. Python (Flask)
Các nhà phát triển Flask nên sử dụng phần mở rộng flask-cors. Nó gọn gàng hơn nhiều so với việc chèn header thủ công vào từng route.
# Cài đặt: pip install flask-cors
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Lệnh này kích hoạt CORS cho tất cả các route trong ứng dụng
CORS(app)
@app.route("/api/data")
def get_data():
return {"status": "success", "data": "CORS is working!"}
3. Cấu hình Nginx
Đôi khi bạn không thể can thiệp vào mã nguồn ứng dụng. Trong những trường hợp đó, hãy xử lý CORS ở cấp độ reverse proxy. Cách này thường hiệu quả hơn đối với các API có lưu lượng truy cập cao.
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://myapp.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
add_header 'Access-Control-Allow-Origin' 'https://myapp.com' always;
proxy_pass http://backend_cluster;
}
4. Spring Boot (Java)
Các nhà phát triển Java có thể sử dụng annotation @CrossOrigin. Bạn có thể áp dụng nó cho một phương thức đơn lẻ hoặc cho toàn bộ class controller.
@RestController
@RequestMapping("/v1")
public class ApiController {
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
}
Cách xác minh việc sửa lỗi
Đừng chỉ tải lại trang và hy vọng mọi thứ sẽ ổn. Hãy sử dụng hai phương pháp sau để chắc chắn:
- Tab Network: Nhấn F12 và chuyển sang tab Network. Nhấp vào yêu cầu API của bạn. Trong mục Response Headers, bạn sẽ thấy
Access-Control-Allow-Origin. Nếu nó không xuất hiện, nghĩa là cấu hình máy chủ chưa có hiệu lực. - Terminal: Sử dụng cURL để mô phỏng một yêu cầu cross-origin. Chạy lệnh sau:
curl -I -H "Origin: http://localhost:3000" http://api.domain.com/data
Tìm dòng access-control-allow-origin: http://localhost:3000 trong kết quả trả về.
Những lỗi thường gặp
CORS nổi tiếng là rất khó tính. Nếu bạn vẫn gặp lỗi, hãy kiểm tra ba nguyên nhân phổ biến sau:
- Giao thức không khớp:
http://domain.comvàhttps://domain.comlà các origin khác nhau. Nếu frontend của bạn chạy trên HTTPS nhưng API lại chạy trên HTTP, trình duyệt sẽ chặn nó. - Dấu gạch chéo cuối: Một số máy chủ coi
http://localhost:3000vàhttp://localhost:3000/(có dấu gạch chéo) là các origin khác nhau. Hãy thống nhất cách sử dụng. - Thông tin xác thực và Ký tự đại diện: Nếu bạn đang gửi cookie hoặc header
Authorization, bạn không thể sử dụng*làm origin. Bạn phải chỉ định chính xác tên miền và thiết lậpAccess-Control-Allow-Credentials: true.
Khi bạn đưa các dải IP vào danh sách trắng hoặc cấu hình tường lửa cho các yêu cầu này, sự chính xác là rất quan trọng. Tôi thường sử dụng Subnet Calculator trên ToolCraft để xác minh các dải CIDR một cách nhanh chóng. Nó đảm bảo API gateway của bạn vẫn có thể truy cập được bởi các dịch vụ nội bộ mà không vô tình để lộ hạ tầng của bạn ra internet công cộng.
Bảng tra cứu nhanh: Các CORS Header quan trọng
Header
Chức năng
`Access-Control-Allow-Origin`
Xác định ai được phép giao tiếp với API.
`Access-Control-Allow-Methods`
Liệt kê các phương thức HTTP được phép (ví dụ: GET hoặc DELETE).
`Access-Control-Max-Age`
Cho trình duyệt biết cần lưu bộ nhớ đệm (cache) quyền CORS trong bao nhiêu giây (ví dụ: 86400).

