為什麼需要動態 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. 核心流程
// 3. 從 API 取得動態內容 const dynamicUrls = await fetchAllPages()
// 4. 組合並生成 XML const xml = generateSitemapXml([...staticUrls, ...dynamicUrls])
// 5. 更新快取並回傳 updateCache(xml) return xml })
3. 關鍵功能實作
A. 快取機制
我們實作了兩層快取:
這樣做的好處:
- 減少對後端 API 的請求壓力
- 加快回應速度
- 透過
X-Cacheheader 可以監控快取效果
B. 分頁處理
當 API 回傳的資料需要分頁時:
${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. 多語系網站
/${lang}/article/${item.id},
lastmod: item.updatedAt
}))
)2. 分類頁面
/category/${cat.slug},
lastmod: cat.updatedAt,
changefreq: 'daily',
priority: '0.8'
}))3. 優先級設定
效能優化建議
1. 控制快取大小
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. 本地測試
bash npm run dev // 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
可復用的模板和 MD 檔案
為了讓團隊其他成員也能快速實作類似功能,我們整理了一個通用模板,以及給 ai 讀取的 md 檔案。
- API 端點: 改成你的實際 API 路徑
- 靜態頁面列表: 加入專案的靜態頁面
- XML 結構: 根據需求調整欄位
- 快取設定: 依據更新頻率調整時間
這樣每次有新專案需要 sitemap 時,只要複製模板檔案並調整設定,給 ai 生調整一下細節,
不到 10 分鐘就能完成。
總結
使用 Nuxt Server Routes 實作動態 sitemap 的優點:
✅ 即時性: 內容更新後立即反映在 sitemap
✅ 自動化: 無需手動維護或重新 build
✅ 彈性: 完全掌控生成邏輯和快取策略
✅ 效能: 透過記憶體快取達到毫秒級回應
✅ 可維護: 程式碼集中管理,易於修改和擴充
這個方案已經在我們多個正式專案中穩定運行,包括政府機關網站和大型企業官網。如果你也在用 Nuxt 3 開發需要 SEO 的專案,不妨試試這個做法!