開發 Next.js 應用程式時,處理來自外部網域的圖片資源經常會遇到跨源資源共享的阻礙。Next.js CORS 問題通常發生在我們嘗試對外部圖片執行 Canvas 操作、套用特定安全策略,或在原生標籤中使用跨域屬性時。想了解基礎 CORS 運作機制與瀏覽器安全策略細節,可先參考站內的 CORS 錯誤是什麼? 如何解決本地端跨域請求 CORS Error 教學。當我們在專案中使用原生 <img> 標籤並加上 crossorigin="anonymous" 屬性時,若圖片伺服器未正確回應對應的標頭,往往會導致圖片載入失敗。本文將解析此問題的成因,並提供透過 next.config.js 設定與後端標頭調整的具體解決方案。
一、 問題成因與規格對照
在 Next.js 專案中,當開發者試圖對外部圖片執行 Canvas 操作或套用特定安全策略而加上 crossorigin="anonymous" 屬性時,若遠端伺服器未正確設定 CORS 標頭,就會觸發阻擋機制。
crossorigin 屬性規格對照表
| 屬性值 | 描述說明 | 伺服器端需求 |
|---|---|---|
anonymous | 發送不帶用戶憑證的跨域請求。 | 伺服器需回應 Access-Control-Allow-Origin。 |
use-credentials | 發送包含 Cookie 等憑證的請求。 | 伺服器需明確允許特定來源與憑證。 |
| 無屬性 | 不強制套用 CORS 檢查規則。 | 適用於一般靜態資源載入。 |
二、 核心解法與程式碼實作
為了充分發揮框架效能並避免跨域衝突,建議優先使用 Next.js 內建的 <Image> 元件,並在設定檔中明確宣告允許載入的遠端圖片來源。若必須使用原生標籤或處理底層請求,則需同步調整伺服器端標頭。
1. next.config.js 的 remotePatterns 設定
當圖片來自外部網域(例如 CDN 或第三方圖床)時,必須在 next.config.js 中進行設定,讓框架能夠安全地抓取並進行優化:
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/images/**',
},
],
},
}
module.exports = nextConfig
2. 伺服器端(Node.js / Express)CORS 標頭設定
若專案必須使用原生 <img> 標籤並啟用 crossorigin="anonymous",圖片所在的伺服器必須在 HTTP 回應中帶入正確的標頭。以下為使用 Express 框架設定跨域回應的範例:
const express = require('express');
const app = express();
// 設定全局或特定路由的 CORS 標頭
app.use('/images', (req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type');
next();
});
app.use('/images', express.static('public/images'));
app.listen(3000, () => {
console.log('Image server running on port 3000');
});
三、 部署與維運的 2 大隱藏踩坑點
在將 Next.js 專案部署至生產環境時,除了正確設定基本的跨域標頭外,還必須注意以下兩項常被忽略的邊界條件,以確保圖片資源在各種網路環境下都能穩定載入。
1. CDN 快取汙染與 Vary: Origin 標頭遺漏
- 問題原因:當圖片伺服器(如 Cloudflare、CloudFront 等 CDN)直接回應
Access-Control-Allow-Origin: *給帶有Origin標頭的跨域請求時,CDN 往往會將這份回應連同 CORS 標頭一併快取起來。若後續有另一個不帶Origin標頭(或來自不同網域)的請求存取同一 URL,CDN 可能會直接回傳帶有舊跨源標頭的快取,導致某些安全性要求嚴格的瀏覽器發生未預期的阻擋或快取錯亂。 - 解法:圖片伺服器在回傳動態 CORS 標頭時,務必同時設定
Vary: Origin回應標頭。這能強制 CDN 根據不同的Origin請求標頭分開快取,避免跨網域快取汙染:res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*'); res.setHeader('Vary', 'Origin'); // 關鍵防呆設定
2. 混合內容與 HTTPS 協定強制對齊
- 問題原因:在本地開發環境(
http://localhost:3000)測試順利,但一上線到正式 HTTPS 環境時,Next.js 的<Image>或原生<img>請求外部 HTTP 圖片資源,遭到瀏覽器直接阻擋並拋出 CORS 或者是 Mixed Content 錯誤。許多開發者誤以為是伺服器 CORS 標頭遺失,實際上是瀏覽器全面禁止安全網頁(HTTPS)載入不安全來源(HTTP)。 - 解法:檢查
next.config.js的remotePatterns宣告中,protocol是否嚴格指定為https;同時,遠端圖片伺服器所輸出的圖片絕對網址也必須全面強制使用 HTTPS,避免前端動態拼接出 HTTP 網址。
四、 常見問題 (FAQ)
Q1:為什麼加上 crossorigin="anonymous" 後,部分圖片會無法顯示?
當瀏覽器偵測到跨域請求帶有 crossorigin 屬性時,會強制發送 Preflight(預檢請求)並檢查伺服器回傳的 Access-Control-Allow-Origin。若伺服器未回應該標頭,瀏覽器基於安全性會直接阻擋資源載入。
Q2:使用 Next.js 的 Image 元件還需要設定 CORS 嗎?
不需要。Next.js 的優化機制是透過伺服器端代理抓取外部圖片,因此不會受到瀏覽器端 CORS 政策的直接限制,開發者只需要在 next.config.js 設定 remotePatterns 即可。
Q3:如何驗證圖片伺服器是否正確回傳標頭?
可以透過瀏覽器的開發者工具(F12)切換至 Network 分頁,點擊該圖片請求,並檢查 Response Headers 中是否包含 access-control-allow-origin。
總結
理解 CORS 機制與瀏覽器安全策略是現代網頁開發的基礎。透過正確配置 Next.js 的遠端圖片來源,或是確保圖片伺服器回傳合適的標頭,能夠有效排除跨域載入失敗的問題,確保應用程式穩定運行。
參考資料與延伸閱讀
- Next.js 官方文件:next.config.js 配置選項 – remotePatterns
- Next.js 官方文件:Image 元件與外部圖片優化實作
- MDN Web Docs:CORS (Cross-Origin Resource Sharing) 核心協定說明
- MDN Web Docs:HTML img 元素之 crossorigin 屬性規範
- MDN Web Docs:Access-Control-Allow-Origin HTTP 回應標頭
- 延伸閱讀:如何使用Chrome套件解決Localhost開發中的CORS問題 – 前端無痛解決 CORS Error 問題
- 延伸閱讀:Next.js 開發問題:解決 “net::ERR_BLOCKED_BY_CLIENT” 錯誤與Content Security Policy(CSP)的關聯
發佈留言