
Bắt Tay CORS: "Cảnh Sát Biên Giới" Cho API Node.js Của Bạn!
Chào các chiến thần Gen Z! Hôm nay, thầy Creyt sẽ giải mã một trong những nỗi ám ảnh kinh hoàng nhất của dân dev frontend khi "bắt tay" với backend: lỗi CORS. Nghe tên đã thấy "khoai" rồi đúng không? Đừng lo, với package cors trong Node.js, chúng ta sẽ biến nỗi sợ hãi này thành món khai vị!
1. CORS là cái quái gì và để làm gì?
Để dễ hình dung, các bạn cứ tưởng tượng thế này:
Bạn là chủ một quán bar cực kỳ xịn xò (chính là cái API backend Node.js của bạn đấy). Khách hàng (là cái ứng dụng frontend bạn đang code, chạy trên React, Angular, Vue, hay thậm chí là một trang HTML đơn giản) muốn vào bar của bạn để gọi đồ (gửi request lấy dữ liệu).
Nhưng mà, quán bar của bạn lại có một "cảnh sát biên giới" cực kỳ nghiêm ngặt (tên nó là Same-Origin Policy - SOP, chính sách bảo mật của trình duyệt). Ông cảnh sát này chỉ cho phép những vị khách đến từ "cùng một khu phố" (cùng một origin - tức là cùng giao thức, domain và port) vào bar thôi. Ví dụ, nếu website của bạn chạy ở https://app.example.com, thì nó chỉ được phép gọi API từ https://api.example.com hoặc https://app.example.com/api thôi.
Nếu có một vị khách từ "khu phố khác" (ví dụ, frontend của bạn đang chạy ở http://localhost:3000 mà muốn gọi API ở http://localhost:5000, hoặc một website evil.com muốn gọi API của bạn) mà không có "giấy phép đặc biệt" thì sao? Ông cảnh sát sẽ "gào thét" lên một cái lỗi quen thuộc: "CORS Error!" và không cho vị khách đó vào.
Vậy, CORS (Cross-Origin Resource Sharing) chính là cái "giấy phép đặc biệt" mà quán bar của bạn (server) cấp cho những vị khách "ngoại quốc" đó. Nó là một cơ chế bảo mật cho phép server kiểm soát xem những "khu phố" nào được phép truy cập tài nguyên của mình. Mục đích là để ngăn chặn các website độc hại truy cập dữ liệu của bạn mà không được phép.
Package cors trong Node.js (thường dùng với Express.js) chính là "ông chủ quán bar" có kinh nghiệm, giúp bạn dễ dàng quản lý và cấp những "giấy phép" này một cách gọn gàng, an toàn, không cần phải tự mình viết luật lệ phức tạp.
2. Code Ví Dụ Minh Họa: Mở Cửa Quán Bar Một Cách Thông Minh
Đầu tiên, bạn cần cài đặt cors và express:
npm install cors express
Giờ thì xem cách chúng ta "thuần hóa" nó:
Ví dụ 1: Mở cửa cho tất cả (chỉ dùng khi dev thôi nhé!)
Đây là cách nhanh nhất để "tắt" lỗi CORS khi đang phát triển. Giống như bạn mở toang cửa quán bar, ai vào cũng được. Thầy Creyt nhắc lại: CHỈ DÙNG KHI DEV THÔI!
const express = require('express');
const cors = require('cors');
const app = express();
// Sử dụng cors middleware
// Điều này cho phép MỌI origin truy cập API của bạn.
// CỰC KỲ KHÔNG AN TOÀN TRONG PRODUCTION!
app.use(cors());
// Một route ví dụ
app.get('/data', (req, res) => {
res.json({ message: 'Đây là dữ liệu từ server của bạn!' });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server đang chạy trên cổng ${PORT}`);
});
Ví dụ 2: Mở cửa có chọn lọc (Cách dùng chuẩn chỉ)
Đây là cách mà thầy Creyt khuyên dùng trong hầu hết các trường hợp, đặc biệt là khi đưa lên production. Bạn chỉ cho phép những "khu phố" (origins) cụ thể vào bar của bạn thôi.
const express = require('express');
const cors = require('cors');
const app = express();
// Cấu hình CORS để chỉ cho phép các origin cụ thể
const corsOptions = {
origin: ['http://localhost:3000', 'https://your-frontend-app.com'], // Danh sách các origin được phép
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // Các HTTP methods được phép
credentials: true, // Cho phép gửi cookies, authorization headers, v.v.
optionsSuccessStatus: 204 // Một số trình duyệt cũ hơn có thể cần status này
};
// Áp dụng cấu hình CORS
app.use(cors(corsOptions));
// Một route ví dụ
app.get('/secure-data', (req, res) => {
// Giả sử bạn có middleware xác thực ở đây
res.json({ message: 'Đây là dữ liệu bảo mật từ server!' });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server đang chạy trên cổng ${PORT}`);
});
Giải thích chi tiết các corsOptions:
origin: Quan trọng nhất! Đây là danh sách các domain (hoặc một domain duy nhất dưới dạng string) mà bạn cho phép truy cập API. Nếu request đến từ một origin không có trong danh sách, nó sẽ bị chặn.methods: Các HTTP method (GET, POST, PUT, DELETE,...) mà các origin được phép sử dụng. Mặc định,corscho phép tất cả các method tiêu chuẩn.credentials: Khitrue, cho phép trình duyệt gửi cookie, HTTP authentication headers (ví dụ:Authorization) cùng với cross-origin request. Lưu ý: Nếu bạn đặtcredentials: true, bạn không thể dùngorigin: '*'. Phải chỉ địnhorigincụ thể!allowedHeaders: Các HTTP header mà client được phép gửi trong request cross-origin. Mặc định, một số header cơ bản đã được cho phép.exposedHeaders: Các HTTP header mà client được phép đọc từ response cross-origin (mặc định trình duyệt chỉ cho phép đọc một số header cơ bản).

3. Mẹo (Best Practices) để ghi nhớ và dùng thực tế
Thầy Creyt có vài chiêu để các bạn "ăn điểm" với CORS:
- Đừng bao giờ
app.use(cors())trong production! (Trừ khi bạn là một hacker có đạo đức và đang thử nghiệm). Nó như mở toang cửa cho mọi người, kể cả trộm cướp vào nhà bạn. Hậu quả là dữ liệu của bạn có thể bị đánh cắp hoặc bị lợi dụng. - Luôn chỉ định
originrõ ràng và cụ thể. Đây là "kim chỉ nam" để bảo vệ API của bạn. Chỉ cấp "giấy phép" cho những ai bạn tin tưởng. - Hiểu về
credentials: true: Dùng cái này khi bạn cần gửi cookie hoặc authorization token qua các request cross-origin (ví dụ, để duy trì trạng thái đăng nhập). Nhớ là khi bậtcredentials,originbắt buộc phải là một domain cụ thể, không được dùng*. - Preflight requests (OPTIONS): Khi client gửi một request "phức tạp" (ví dụ: dùng method khác GET/POST đơn giản, hoặc có custom header), trình duyệt sẽ tự động gửi một request
OPTIONStrước (gọi là "preflight request") để hỏi server xem request chính có được phép hay không. Packagecorstự động xử lý các preflight request này cho bạn, bạn không cần phải làm gì thêm. - Thứ tự Middleware: Luôn đặt
app.use(cors(corsOptions))trước các route xử lý request của bạn. Nếu không, request có thể bị chặn bởi các route khác trước khicorskịp xử lý.
4. Ví dụ thực tế các ứng dụng/website đã ứng dụng
CORS không phải là thứ gì đó xa vời, nó hiện diện ở khắp mọi nơi bạn thấy frontend và backend "tách đôi":
- Các ứng dụng SPA (Single Page Applications): Hầu hết các ứng dụng React, Angular, Vue.js hiện đại đều chạy trên một domain riêng (ví dụ:
app.yourcompany.com) và gọi API từ một domain khác (ví dụ:api.yourcompany.com). CORS là bắt buộc để chúng có thể giao tiếp được. - Mobile Apps: Khi ứng dụng di động của bạn (iOS/Android) gọi đến một backend API, về lý thuyết thì không bị CORS vì mobile app không phải là trình duyệt. Tuy nhiên, khi bạn phát triển một Admin Panel hoặc Web Portal cho mobile app đó, bạn lại quay về câu chuyện CORS.
- Microservices: Nếu bạn có nhiều dịch vụ nhỏ giao tiếp với nhau, và một trong số chúng là một "cổng" (Gateway) mà frontend web gọi đến, thì CORS sẽ phát huy tác dụng ở đó.
- Ví dụ cụ thể: Bạn đang code một ứng dụng thương mại điện tử. Frontend của bạn chạy trên
localhost:3000(khi dev) hoặcshop.mycompany.com(khi deploy). Backend API của bạn chạy trênlocalhost:5000(khi dev) hoặcapi.mycompany.com(khi deploy). Khi frontend cố gắngfetch('/products')từ backend, nếu không có CORS, trình duyệt sẽ chặn đứng và báo lỗi.
5. Thử nghiệm và Hướng dẫn nên dùng cho case nào
-
Trong môi trường Development (dev):
- Bạn có thể dùng
app.use(cors())một cách an toàn để "tắt" lỗi CORS và tập trung vào việc phát triển tính năng. Đừng quên thay đổi nó khi deploy nhé! - Hoặc tốt hơn, dùng
cors({ origin: 'http://localhost:3000' })nếu frontend của bạn chạy trên cổng 3000.
- Bạn có thể dùng
-
Trong môi trường Production (prod):
- BẮT BUỘC phải chỉ định
origincụ thể. Ví dụ:cors({ origin: 'https://your-frontend-app.com' })hoặc một mảng các domain nếu bạn có nhiều frontend. - Nếu bạn có nhiều subdomain, có thể dùng regex (nhưng cẩn thận).
- BẮT BUỘC phải chỉ định
-
API công khai (Public API):
- Nếu bạn đang xây dựng một API mà bất kỳ ai cũng có thể sử dụng (ví dụ: API thời tiết, API dữ liệu công cộng), bạn có thể cân nhắc mở rộng
originhơn, thậm chí là*(nhưng vẫn nên cân nhắc kỹ về bảo mật, đặc biệt nếu có dữ liệu nhạy cảm). Thường thì các Public API sẽ yêu cầu API Key thay vì dựa vào CORS để bảo mật.
- Nếu bạn đang xây dựng một API mà bất kỳ ai cũng có thể sử dụng (ví dụ: API thời tiết, API dữ liệu công cộng), bạn có thể cân nhắc mở rộng
-
API nội bộ/Microservices không qua trình duyệt:
- Nếu các dịch vụ backend của bạn giao tiếp với nhau mà không có trình duyệt nào liên quan, bạn không cần quan tâm đến CORS. CORS là một cơ chế bảo mật của trình duyệt, không phải của server.
Nhớ nhé các bạn, CORS không phải là kẻ thù, nó là một "vệ sĩ" mà chúng ta cần biết cách điều khiển. Hiểu rõ và sử dụng đúng cors package sẽ giúp API của bạn vừa mạnh mẽ, vừa an toàn, và quan trọng nhất là không còn gây "đau đầu" cho frontend nữa! Cứ thế mà triển thôi!
Thuộc Series: Nodejs
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!