Lập trình

Cách sửa lỗi CORS

“Blocked by CORS policy” là cơ chế bảo vệ người dùng của trình duyệt, không phải lỗi trong mã của bạn. Cách sửa luôn nằm ở máy chủ nhận yêu cầu. Hướng dẫn này giải thích trình duyệt kiểm tra những gì và đưa ra cấu hình chạy được cho các trường hợp phổ biến.

Trung cấp · 9 phút đọc · Cập nhật 30 tháng 10, 2026

Cách sửa lỗi CORS

CORS thực sự là gì

Trình duyệt sẽ chặn JavaScript trên https://app.example.com đọc phản hồi từ một origin khác (scheme + host + port), chẳng hạn https://api.example.com, trừ khi máy chủ đó cho phép. Máy chủ cho phép bằng các header phản hồi Access-Control-Allow-*. Yêu cầu gửi từ curl, Postman hay backend của bạn không bị ảnh hưởng, nên mới có chuyện “chạy được trên Postman nhưng lỗi trên trình duyệt”.

Đọc thông báo lỗi

  • “No ‘Access-Control-Allow-Origin’ header is present” — máy chủ không gửi header CORS nào, hoặc trả về trang lỗi (404, 500) mà không kèm header đó.
  • “Response to preflight request doesn’t pass access control check” — yêu cầu OPTIONS bị lỗi: máy chủ không xử lý, trả về lỗi hoặc thiếu header.
  • “The value of the ‘Access-Control-Allow-Origin’ header must not be the wildcard ‘*’ when credentials mode is ‘include’” — bạn đang gửi cookie, nên máy chủ phải trả về đúng origin của yêu cầu.

Hãy xem yêu cầu lỗi trong DevTools → Network, hoặc kiểm tra header phản hồi thực tế bằng HTTP Header Checker.

Yêu cầu đơn giản và preflight

Một yêu cầu được coi là “đơn giản” nếu là GET, HEAD hoặc POST chỉ có header cơ bản và phần thân dạng form hoặc văn bản thuần. Mọi yêu cầu khác, như Content-Type: application/json, header Authorization, PUT hay DELETE, sẽ khiến trình duyệt gửi trước một yêu cầu OPTIONS gọi là preflight. Máy chủ của bạn phải phản hồi nó với trạng thái 204 hoặc 200 cùng các header sau:

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: 600

Cấu hình chạy được

Express với gói cors:

const cors = require('cors');
app.use(cors({
  origin: ['https://app.example.com'],
  credentials: true,                 // chỉ bật khi bạn gửi cookie
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

Nginx:

location /api/ {
  if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin "https://app.example.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
    add_header Access-Control-Max-Age 600;
    return 204;
  }
  add_header Access-Control-Allow-Origin "https://app.example.com" always;
  proxy_pass http://backend;
}

Tham số always rất quan trọng: nếu thiếu, Nginx sẽ bỏ header ở các phản hồi lỗi, và trình duyệt sẽ báo lỗi CORS thay vì lỗi 500 thật sự. Để tạo header cho các máy chủ khác (Vercel, Netlify, Cloudflare Workers, Apache), hãy dùng CORS Header Generator.

Cookie và thông tin xác thực

Để gửi cookie qua nhiều origin, yêu cầu cần có credentials: 'include' (fetch) và máy chủ phải trả về Access-Control-Allow-Credentials: true cùng đúng origin, tuyệt đối không dùng *. Bản thân cookie cần có SameSite=None; Secure. Khi bạn trả về origin lấy từ một danh sách, hãy gửi thêm Vary: Origin để cache không trả header của site này cho site khác.

Những việc không nên làm

  • Không phản hồi lại mọi giá trị Origin khi đã bật credentials, vì điều đó cho phép mọi website đọc dữ liệu của người dùng bạn.
  • Đừng “sửa” CORS bằng tiện ích trình duyệt hay proxy công khai; cách này chỉ che giấu vấn đề trên máy của bạn.
  • Nếu API là của bạn và nằm cùng site, dùng reverse proxy (cùng origin) sẽ loại bỏ hoàn toàn CORS.

Tái hiện yêu cầu của trình duyệt bằng API Tester, hoặc chuyển nó thành mã bằng cURL to Code.

Câu hỏi thường gặp

Có thể sửa CORS ở phía frontend không?
Không. CORS do trình duyệt áp dụng dựa trên header phản hồi của máy chủ. Hãy sửa máy chủ, hoặc chuyển yêu cầu qua backend của riêng bạn hoặc một proxy cùng origin.
Vì sao chạy được trên Postman nhưng không chạy trên trình duyệt?
Postman, curl và các máy chủ không áp dụng CORS; chỉ trình duyệt mới áp dụng, nhằm bảo vệ dữ liệu người dùng trên các site khác.
Access-Control-Allow-Origin: * có an toàn không?
Với API công khai, chỉ đọc và không dùng cookie thì có. Không thể dùng cùng credentials, và API riêng tư nên liệt kê rõ các origin được phép.

Đọc tiếp