Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Chắc hẳn bạn đã từng gặp thông báo đỏ lòm trong console: "blocked by CORS policy". Rất nhiều người mới phản ứng bằng cách tìm một đoạn mã dán vào cho hết lỗi mà không hiểu nguyên nhân. Bài này giải thích CORS là gì, tại sao nó tồn tại, và cách xử lý đúng.
Một origin gồm ba phần: giao thức, tên miền và cổng. Ví dụ https://app.example.com và https://api.example.com là hai origin khác nhau, http://localhost:3000 và http://localhost:5173 cũng vậy.
Trình duyệt áp dụng chính sách cùng nguồn gốc (same-origin policy): mã JavaScript chạy ở origin này mặc định không được đọc phản hồi từ origin khác. Đây là biện pháp bảo vệ quan trọng. Nếu không, một trang web độc hại bạn vừa mở có thể dùng phiên đăng nhập của bạn để đọc dữ liệu từ ngân hàng hay email trong tab khác.
CORS (Cross-Origin Resource Sharing) là cơ chế cho phép máy chủ nới lỏng có kiểm soát chính sách trên. Máy chủ khai báo qua header HTTP rằng origin nào được phép đọc phản hồi. Hai điều cần ghi nhớ:
Trang ở https://app.example.com gọi API ở https://api.example.com. Trình duyệt tự thêm header Origin vào yêu cầu. Nếu máy chủ trả về:
Access-Control-Allow-Origin: https://app.example.comthì trình duyệt cho phép mã JavaScript đọc phản hồi. Nếu header thiếu hoặc không khớp, phản hồi bị chặn, và bạn thấy lỗi CORS. Lưu ý yêu cầu thực ra vẫn đến được máy chủ, chỉ là kết quả bị giấu khỏi mã của trang.
Với yêu cầu "không đơn giản", chẳng hạn dùng method như PUT hoặc DELETE, hoặc có header tùy chỉnh như Authorization, hoặc Content-Type: application/json, trình duyệt sẽ gửi trước một yêu cầu OPTIONS để hỏi máy chủ có cho phép không:
OPTIONS /api/bai-viet
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorizationMáy chủ phải trả lời với các header cho phép:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600Chỉ khi preflight thành công, trình duyệt mới gửi yêu cầu thật. Rất nhiều lỗi CORS thực ra là do máy chủ không xử lý đúng yêu cầu OPTIONS (ví dụ trả về 404 hoặc 401).
Với Express (Node.js), có thể dùng gói cors:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: ['https://app.example.com', 'http://localhost:5173'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
}));Các framework khác (Laravel, Django, Spring, ASP.NET...) đều có middleware hoặc cấu hình tương tự. Hãy khai báo danh sách origin cụ thể thay vì để mở hoàn toàn.
Nếu frontend cần gửi cookie sang origin khác, phải đặt credentials: 'include' trong fetch, và máy chủ phải trả Access-Control-Allow-Credentials: true. Khi đó không được dùng dấu sao * cho Access-Control-Allow-Origin, mà phải chỉ rõ origin. Cookie còn chịu ảnh hưởng của thuộc tính SameSite và Secure.
Access-Control-Allow-Origin: * cho mọi API: chỉ chấp nhận được với dữ liệu thật sự công khai. Với API có xác thực, hãy giới hạn origin./api sang máy chủ backend, nên trình duyệt thấy cùng origin trong lúc phát triển.CORS không phải là lỗi để "vượt qua" mà là một lớp bảo vệ. Hiểu rằng nó do trình duyệt thực thi và máy chủ quyết định cho phép giúp bạn sửa đúng chỗ: cấu hình header trên API, chỉ định origin cụ thể và xử lý tốt yêu cầu preflight.
Để xây dựng đầy đủ cả frontend và backend và hiểu cách chúng giao tiếp an toàn, bạn có thể xem các khóa học trên codebem.com.
Nguyễn Đình Cường
0 comment