前端開發常常會遇到「跨來源請求被阻擋」的錯誤訊息,比如: Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present... 這就是著名的 CORS 問題。本篇文章將說明 CORS 是什麼、為什麼會發生,以及常見的解法。 CORS 是什麼? CORS(Cross-Origin Resource Sharing,跨來源資源共享)是一種瀏覽器的安全機制,用來限制「不同網域」之間的請求。簡單來說,它防止了一個網站的 JavaScript 去隨意讀取另一個網站的資料。 什麼是「跨來源」? 只要以下任何一個不同,就會被視為「不同來源」: 區塊 範例 協定 http://example.com vs https://example.com 網域 api.example.com vs www.example.com Port example.com:3000 vs example.com:8000 為什麼會出現 CORS 錯誤? 瀏覽器會阻擋從網頁腳本對其他來源發起的請求(例如使用 fetch、axios)。除非 伺服器端主動聲明允許該請求的來源,否則請求會被攔截。 範例情境 假設前端使用 React (http://localhost:3000),想從後端 API (http://localhost:8000) 取得資料: fetch('http://localhost:8000/api/data') 這是跨來源請求,除非後端有設定 CORS header,否則會被瀏覽器擋下來。 解決 CORS 問題的方法 1. 修改後端設定 CORS 問題應由「伺服器端」解決。需要在伺服器回應中加上正確的 Access-Control-Allow-Origin header。 範例:使用 Express const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors()); // 允許所有來源 // 或只允許特定來源 // app.use(cors({ origin: 'http://localhost:3000' })); app.get('/api/data', (req, res) => { res.json({ message: 'Hello from server!' }); }); app.listen(8000); 範例:使用 Django + django-cors-headers pip install django-cors-headers # settings.py INSTALLED_APPS = [ ... 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', ... ] # 允許所有網域 CORS_ALLOW_ALL_ORIGINS = True # 或只允許特定網域 # CORS_ALLOWED_ORIGINS = [ # "http://localhost:3000", # ] 2. 使用 Proxy 避開 CORS 開發時可使用前端代理轉發請求,例如 React: // vite.config.js or package.json proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, }, } 這樣 fetch('/api/data') 實際會被代理成後端的請求,不會被視為跨來源。 3. 後端設定 Access-Control Headers 除了 Access-Control-Allow-Origin,有時也需要加上這些 header: Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization 這些設定也必須在「預檢請求(Preflight Request)」中正確處理。 面試題目 「請說明什麼是 CORS(Cross-Origin Resource Sharing),以及如果遇到 CORS 問題該如何解決?」 回答範例: CORS(Cross-Origin Resource Sharing) 是一種瀏覽器的安全機制,用來限制前端從不同來源(origin)去請求資源,避免惡意網站竊取資料。當前端的 JavaScript 嘗試向不同網域、協定或 port 發送請求時,如果伺服器沒有正確設定 CORS header,瀏覽器會阻擋這個請求。 常見錯誤: 例如使用 fetch 或 axios 向不同來源的 API 發送請求時,會看到類似錯誤: Access to fetch at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy 解決方式: 從伺服器端設定 CORS header(這是正確的做法): 設定 Access-Control-Allow-Origin,明確允許某個前端網域。 可搭配套件,如: Node.js 可用 cors middleware Django 可用 django-cors-headers 本地開發時使用 proxy 轉發請求,避開跨域問題(開發用): 例如 React 可以設定 vite.config.js 或 webpack devServer proxy 總結 問題 解法 跨來源請求被阻擋 在後端加上 CORS Header 特定網域允許 設定 Access-Control-Allow-Origin 為指定來源 多來源需求 使用動態設定或 whitelist 本地開發測試 使用 Proxy 或開啟允許全部來源 延伸閱讀 MDN - HTTP access control (CORS) CORS 官方規範 (W3C) django-cors-headers GitHub 如果曾經在開發中遇過 CORS 錯誤,不妨回頭看看是不是跨來源造成的限制,並從伺服器端著手解決吧!