什麼是 CORS(Cross-Origin Resource Sharing)? 該怎麼解決跨來源請求問題?

前端開發常常會遇到「跨來源請求被阻擋」的錯誤訊息,比如:

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 錯誤?

瀏覽器會阻擋從網頁腳本對其他來源發起的請求(例如使用 fetchaxios)。除非 伺服器端主動聲明允許該請求的來源,否則請求會被攔截。

範例情境

假設前端使用 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

解決方式:

  1. 從伺服器端設定 CORS header(這是正確的做法):

    • 設定 Access-Control-Allow-Origin,明確允許某個前端網域。

    • 可搭配套件,如:

      • Node.js 可用 cors middleware
      • Django 可用 django-cors-headers
  2. 本地開發時使用 proxy 轉發請求,避開跨域問題(開發用):

    • 例如 React 可以設定 vite.config.jswebpack devServer proxy

總結

問題 解法
跨來源請求被阻擋 在後端加上 CORS Header
特定網域允許 設定 Access-Control-Allow-Origin 為指定來源
多來源需求 使用動態設定或 whitelist
本地開發測試 使用 Proxy 或開啟允許全部來源

延伸閱讀


如果曾經在開發中遇過 CORS 錯誤,不妨回頭看看是不是跨來源造成的限制,並從伺服器端著手解決吧!