Bạn đã bao giờ gặp lỗi CORS policy error khi gọi API từ một domain khác chưa? Bạn viết code hoàn hảo, API chạy tốt, nhưng trình duyệt lại từ chối phản hồi chỉ vì lý do "chính sách bảo mật"!
Đây là một vấn đề rất phổ biến khi làm việc với các ứng dụng web hiện đại. Đặc biệt nếu bạn đang phát triển ứng dụng frontend (React, Vue, Angular) gọi API từ một backend khác, hoặc xây dựng hệ thống microservices, bạn chắc chắn sẽ gặp lỗi CORS ít nhất một lần.
Vậy CORS là gì? Tại sao trình duyệt lại chặn yêu cầu giữa các domain khác nhau? Và làm sao để khắc phục lỗi CORS đúng cách mà không làm ảnh hưởng đến bảo mật hệ thống?
Hãy cùng khám phá trong bài viết này! 🚀
1. Giới thiệu về CORS
CORS (Cross-Origin Resource Sharing - Chia sẻ tài nguyên giữa các nguồn gốc khác nhau) là một cơ chế bảo mật của trình duyệt nhằm ngăn chặn các trang web khác nhau chia sẻ tài nguyên với nhau nếu không được phép.
Ví dụ: Khi một trang web chạy trên domain A (https://domain-a.com) muốn gọi API từ domain B (https://api.domain-b.com), trình duyệt sẽ chặn yêu cầu này nếu domain B không cho phép.
Tại sao lại có CORS?
- Để ngăn chặn các cuộc tấn công bảo mật, chẳng hạn như Cross-Site Request Forgery (CSRF).
- Để bảo vệ dữ liệu người dùng không bị đánh cắp bởi các trang web không đáng tin cậy.
2. CORS hoạt động như thế nào?
Trình duyệt kiểm tra CORS dựa trên HTTP headers mà server gửi về. Nếu server cho phép yêu cầu từ một nguồn khác, trình duyệt sẽ chấp nhận phản hồi, ngược lại sẽ chặn yêu cầu.
Quy trình kiểm tra CORS
- Trình duyệt gửi yêu cầu đến server kèm theo Origin header (nguồn gốc của yêu cầu).
- Server kiểm tra Origin và quyết định có cho phép truy cập hay không.
- Nếu được phép, server trả về Access-Control-Allow-Origin.
- Nếu không được phép, trình duyệt chặn yêu cầu và hiển thị lỗi CORS.
Ví dụ yêu cầu từ trình duyệt:
GET /data HTTP/1.1
Host: api.domain-b.com
Origin: https://domain-a.comNếu server chấp nhận, nó sẽ trả về:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://domain-a.comNgược lại, nếu server không hỗ trợ CORS, trình duyệt sẽ chặn yêu cầu.
3. Các loại yêu cầu CORS
CORS được chia thành 3 loại chính:
3.1. Simple Requests (Yêu cầu đơn giản)
Nếu một request thỏa mãn các điều kiện sau, trình duyệt gửi request trực tiếp mà không cần kiểm tra trước:
- Chỉ sử dụng các phương thức:
GET,POST,HEAD - Không chứa headers tùy chỉnh (
Authorization,Content-Type: application/json) - Không có
XMLHttpRequest.withCredentials = true
Ví dụ: Một request hợp lệ
fetch("https://api.domain-b.com/data", {
method: "GET",
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error));3.2. Preflight Requests (Yêu cầu kiểm tra trước)
Nếu request có:
- Các phương thức không chuẩn (
PUT,DELETE,PATCH,OPTIONS) - Headers tùy chỉnh (
Authorization,X-Token,Content-Type: application/json) XMLHttpRequest.withCredentials = true
Trình duyệt sẽ gửi yêu cầu kiểm tra trước (OPTIONS request) trước khi gửi yêu cầu chính.
Ví dụ: Request bằng PUT
fetch("https://api.domain-b.com/data", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer my-token"
},
body: JSON.stringify({ name: "CodeTutHub" })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error));Trình duyệt sẽ gửi một request OPTIONS trước:
OPTIONS /data HTTP/1.1
Host: api.domain-b.com
Origin: https://domain-a.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization, Content-TypeServer phải trả về:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://domain-a.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type3.3. Credentialed Requests (Yêu cầu có xác thực)
Nếu bạn muốn gửi cookie hoặc thông tin xác thực (Authorization token), bạn cần:
credentials: 'include'trong JavaScript.Access-Control-Allow-Credentials: truetrong server.
Ví dụ:
fetch("https://api.domain-b.com/protected", {
method: "GET",
credentials: "include"
})Server phải phản hồi:
Access-Control-Allow-Origin: https://domain-a.com
Access-Control-Allow-Credentials: trueLưu ý:Access-Control-Allow-Origin: * không thể dùng khi có Access-Control-Allow-Credentials: true.
4. Cách khắc phục lỗi CORS
4.1. Cấu hình CORS trên server
Nếu bạn là admin của server, hãy thêm headers vào response.
Cấu hình trong PHP
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");Cấu hình trong Laravel
Sử dụng middleware trong app/Http/Middleware/Cors.php:
public function handle($request, Closure $next)
{
$response = $next($request);
$response->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return $response;
}Đăng ký middleware trong Kernel.php:
protected $middleware = [
\App\Http\Middleware\Cors::class,
];Cấu hình trong Express.js (Node.js)
const cors = require('cors');
app.use(cors({ origin: 'https://domain-a.com', credentials: true }));4.2. Dùng Proxy Server
Nếu bạn không có quyền chỉnh server API, hãy sử dụng proxy để bypass CORS.
Dùng Nginx Reverse Proxy:
location /api/ {
proxy_pass https://api.domain-b.com/;
add_header Access-Control-Allow-Origin *;
}Hoặc dùng CORS Proxy miễn phí như:
fetch("https://cors-anywhere.herokuapp.com/https://api.domain-b.com/data")5. Các lỗi thường gặp và cách xử lý
| Lỗi | Nguyên nhân | Cách khắc phục |
|---|---|---|
| CORS policy error | Server không gửi Access-Control-Allow-Origin | Cấu hình lại server hoặc dùng proxy |
| Preflight request blocked | Server không cho phép phương thức PUT, DELETE | Thêm Access-Control-Allow-Methods trên server |
| Credential request blocked | Không có Access-Control-Allow-Credentials: true | Cấu hình lại server, không dùng * cho Access-Control-Allow-Origin |
6. Kết luận
🔹 CORS là cơ chế bảo mật quan trọng để ngăn chặn việc chia sẻ tài nguyên trái phép giữa các domain.
🔹 Nếu gặp lỗi CORS policy, bạn cần cấu hình lại server hoặc dùng proxy.
🔹 Hãy tối ưu hóa CORS để tránh bị chặn khi tích hợp API từ nguồn khác.
🚀 Hy vọng bài viết này giúp bạn hiểu rõ về CORS! Nếu bạn có câu hỏi, hãy bình luận trên CodeTutHub.com! 🚀









