用 Nuxt Server Routes 打造動態 Sitemap:從靜態到自動化的完整實作
作為一個接案公司的前端工程師,我們經常需要為客戶網站處理 SEO 相關的需求。其中最基本但也最重要的就是 sitemap.xml。傳統做法可能是手動維護或使用套件生成靜態檔案,但當網站內容頻繁更新時,這種方式就顯得不夠彈性。
今天想分享我們團隊在 Nuxt 3 專案中實作動態 sitemap 的經驗,透過 Nuxt 內建的 Server Routes 功能,讓 sitemap 能夠即時反映網站的最新內容。
為什麼需要動態 Sitemap?
在我們接的專案中,像是文化機構網站或企業官網,經常會有以下情況:
- 內容持續更新: 新聞、展覽、活動等內容不斷新增
- 多語系支援: 同一內容可能有多個語言版本
- 大量動態頁面: 透過 API 產生的頁面數量可能達到數百甚至數千頁
- 即時性需求: 希望搜尋引擎能快速收錄新內容
如果使用靜態生成的方式,每次內容更新就需要重新 build 並部署,不僅耗時也容易出錯。動態 sitemap 則能在每次訪問時自動抓取最新資料,完美解決這個痛點。
Nuxt Server Routes 的優勢
Nuxt 3 提供了 Server Routes 功能,讓我們可以在 server/routes/ 目錄下建立 API 端點或動態檔案生成器。相較於其他方案:
- 無需額外套件: 使用 Nuxt 內建功能,減少依賴
- 完全控制: 可以自由決定快取策略、資料來源和生成邏輯
- 與專案整合: 直接使用專案的 runtime config 和 API 設定
- 效能優化: 可以實作記憶體快取,避免每次請求都重新計算
核心實作架構
1. 檔案結構
當使用者訪問 https://your-domain.com/sitemap.xml 時,Nuxt 會自動執行 sitemap.xml.ts 中的程式碼。
2. 核心流程
// 2. 準備靜態頁面 const staticUrls = [ { loc: '/', lastmod: new Date().toISOString() }, { loc: '/about', lastmod: new Date().toISOString() }, // ... 更多靜態頁面 ]
// 3. 從 API 取得動態內容 const dynamicUrls = await fetchAllPages()
// 4. 組合並生成 XML const xml = generateSitemapXml([...staticUrls, ...dynamicUrls])
// 5. 更新快取並回傳 updateCache(xml) return xml })
3. 關鍵功能實作
A. 快取機制
我們實作了兩層快取:
// Browser 快取 setHeader(event, 'Cache-Control', 's-maxage=86400, stale-while-revalidate') setHeader(event, 'X-Cache', fromCache ? 'HIT' : 'MISS')
這樣做的好處:
- 減少對後端 API 的請求壓力
- 加快回應速度
- 透過
X-Cacheheader 可以監控快取效果
B. 分頁處理
當 API 回傳的資料需要分頁時:
while (hasMore) {
const response = await $fetch(${apiUrl}?page=${currentPage}&pageSize=100)
const items = response?.data?.content || []
allItems.push(...items)
const totalPages = response?.data?.pagination?.totalPages || 1 hasMore = currentPage < totalPages currentPage++ }
return allItems.map(item => ({
loc: /article/${item.id},
lastmod: item.updatedAt
}))
}
C. 錯誤處理
實務上,API 可能會失敗或回傳不完整的資料:
D. XML 轉義
處理使用者輸入的內容時,必須進行 XML 轉義:
4. 完整的 Sitemap XML 格式
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${items.map(item => <url>
<loc>${escapeXml(${baseUrl}${item.loc})}</loc>
<lastmod>${item.lastmod}</lastmod>
<changefreq>${item.changefreq || 'weekly'}</changefreq>
<priority>${item.priority || '0.5'}</priority>
</url>).join('\n')}
</urlset>實際應用場景
1. 多語系網站
const multilingualUrls = languages.flatMap(lang =>
dynamicContent.map(item => ({
loc: /${lang}/article/${item.id},
lastmod: item.updatedAt
}))
)
2. 分類頁面
/category/${cat.slug},
lastmod: cat.updatedAt,
changefreq: 'daily',
priority: '0.8'
}))3. 優先級設定
效能優化建議
1. 控制快取大小
if (xml.length < MAXCACHESIZE) { cache = xml cacheTimestamp = Date.now() }
2. API 超時處理
3. 分批處理大量資料
如果頁面數量超過 50,000 筆,建議使用 Sitemap Index:
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>${baseUrl}/sitemap-static.xml</loc>
</sitemap>
<sitemap>
<loc>${baseUrl}/sitemap-articles.xml</loc>
</sitemap>
<sitemap>
<loc>${baseUrl}/sitemap-products.xml</loc>
</sitemap>
</sitemapindex>部署注意事項
1. 環境變數設定
2. 監控和日誌
[Sitemap] Generated with ${items.length} URLs)
console.log([Sitemap] Cache status: ${fromCache ? 'HIT' : 'MISS'})
console.log([Sitemap] XML size: ${(xml.length / 1024).toFixed(2)} KB)3. robots.txt 設定
別忘了在 public/robots.txt 中加入:
測試與驗證
1. 本地測試
訪問 http://localhost:3000/sitemap.xml
2. 檢查快取效果
觀察 Console 輸出或 Response Headers 中的 X-Cache 欄位。
3. XML 格式驗證
使用 Google Search Console 的 Sitemap 測試工具,或線上 XML 驗證器。
4. 效能測試
測試回應時間
curl -w "@curl-format.txt" -o /dev/null -s https://your-domain.com/sitemap.xml實戰經驗分享
在我們實際專案中遇到的一些問題和解法:
問題 1: API 回傳資料不一致
解法: 加入資料驗證和預設值
/article/${item.id},
lastmod: item.updatedAt || new Date().toISOString()
}))問題 2: 記憶體快取在多實例環境失效
解法: 考慮使用 Redis 或調短快取時間
問題 3: 靜態頁面列表難以維護
解法: 從路由設定檔自動產生
const staticUrls = routes .filter(route => !route.path.includes(':')) // 排除動態路由 .map(route => ({ loc: route.path, lastmod: new Date().toISOString() }))
可複用的模板
為了讓團隊其他成員也能快速實作類似功能,我們整理了一個通用模板。只要根據專案需求修改以下幾個部分:
- API 端點: 改成你的實際 API 路徑
- 靜態頁面列表: 加入專案的靜態頁面
- XML 結構: 根據需求調整欄位
- 快取設定: 依據更新頻率調整時間
這樣每次有新專案需要 sitemap 時,只要複製模板檔案並調整設定,不到 10 分鐘就能完成。
總結
使用 Nuxt Server Routes 實作動態 sitemap 的優點:
✅ 即時性: 內容更新後立即反映在 sitemap ✅ 自動化: 無需手動維護或重新 build ✅ 彈性: 完全掌控生成邏輯和快取策略 ✅ 效能: 透過記憶體快取達到毫秒級回應 ✅ 可維護: 程式碼集中管理,易於修改和擴充
這個方案已經在我們多個正式專案中穩定運行,包括政府機關網站和大型企業官網。如果你也在用 Nuxt 3 開發需要 SEO 的專案,不妨試試這個做法!
延伸閱讀
---
有任何問題或想法歡迎交流討論!這個模板我們也開源在團隊的 GitLab,歡迎取用和改進。