← 文章

別讓 Google 找不到你的文章——SSR Blog 的 SEO 踩坑實錄

· 6 min read · 35 次閱讀
Astro SEO SSR Sitemap JSON-LD
SSR Blog 實戰

別讓 Google 找不到你的文章

SSR Blog 的 SEO 踩坑實錄

用 Astro + PostgreSQL 建 Blog 過程中,每一個 SEO 決策背後的原因——以及那些差點讓文章消失在搜尋結果裡的坑。

問題

SSR Blog 的 SEO 為什麼跟靜態站不一樣?#

1

動態內容不在 Sitemap#

SSR 頁面是 runtime 產生的,@astrojs/sitemap 只收錄 build-time 的靜態頁。

文章發了卻不在 sitemap = Google 根本不知道它存在。

2

Tool Schema 不是唯一的隱形成本#

跟 MCP token 一樣,SEO 也有「隱形成本」:meta tag 缺失、hreflang 錯誤、canonical 不一致。

67% 多語言站 hreflang 實作有錯誤

3

SSR 的效能雙面刃#

SSR 讓內容即時更新,但也讓 TTFB 受 DB 查詢時間影響。

沒有快取策略 = 每次 request 都跑 DB query。

技術棧

這個 Blog 的組成#

Astro 5
框架
PostgreSQL
資料庫
Drizzle
ORM 查詢層
Tailwind
樣式
Cloudflare
Tunnel 部署
SEO 決策

我們做了哪些事?#

每一層處理一個 SEO 面向,由上到下各有明確的消費者。

動態 Sitemap
sitemap-posts.xml 從 DB 即時查詢已發布文章,build 時自動 patch 進 sitemap-index.xml
🔍 Google / Bing 爬蟲
JSON-LD 結構化資料
每篇文章自動生成 BlogPosting schema——標題、作者、發布時間、語言全從 DB 欄位對應
📊 搜尋結果豐富摘要
Canonical URL
SSR 頁面自動設定 canonical,指向自己。避免 http://localhosthttps://blog.joneshong.com 被判定重複
🔗 去重機制
hreflang 多語言
zh-TW ↔ en 雙向 alternate link,加 x-default fallback。67% 的站做錯這步
🌐 多語言搜尋
robots.txt
允許爬蟲存取所有公開頁面,阻擋 /admin//api/。指向兩份 sitemap
🤖 爬蟲控制
效能

Core Web Vitals 優化#

0 KB
JS baseline
Astro 預設零 JS
按需
React island hydration
搜尋、圖譜
延遲
字體載入策略
CJK 系統字體 + Latin lazy load
SSR
動態內容
即時更新

Astro 的殺手鐧:預設不送任何 JavaScript。React 元件只在需要互動的地方 hydrate(client:only),其餘全是靜態 HTML。

踩坑紀錄

我們怎麼發現問題的?#

不是預先設計好 SEO 再實作——是每個坑踩下去才發現的。

文章發了 → Google 搜不到

sitemap-posts.xml 沒人引用#

@astrojs/sitemap 生成 sitemap-index.xml 時只包含靜態頁。動態的 sitemap-posts.xml 被無視了。修法:build 後自動 patch sitemap-index 加入 posts sitemap。

領悟:自動化工具不一定覆蓋所有 case,SSR 動態頁需要手動補漏。

12 分鐘的文章顯示 73 min read

Rich HTML 的 content.length 包含整個 CSS#

content.length / 400 算閱讀時間,但 Rich HTML 格式的 content 有 25000+ 字元的 CSS + HTML tags。Strip tags 後才正確。

領悟:任何跟 content 長度相關的邏輯,都要先想清楚「這個 content 是什麼格式」。

Nginx subpath proxy 下頁面空白

Vite dev server + subpath = 死路#

Vite 的 ES module import 用絕對路徑,nginx sub_filter 改不完。解法:dev preview 不用 Vite dev server,改用 built SSR server。

領悟:Astro islands 的 component-url 屬性也需要被 sub_filter 改寫。

帶走這段

複製給你的 AI Agent#

把下面這段話貼給你的 AI coding agent,讓它幫你評估 SSR Blog 的 SEO 設定。

幫我評估這個 SSR Blog 的 SEO 設定有沒有遺漏。 目前已做的: - 動態 sitemap(DB 查詢已發布文章,build 時 patch 進 sitemap-index) - JSON-LD BlogPosting schema(自動從文章欄位生成) - Canonical URL(每頁自動指向自己) - hreflang(zh-TW ↔ en 雙向 alternate) - robots.txt(允許公開頁,阻擋 admin/api) - Astro 零 JS baseline + React islands 按需 hydrate 請幫我檢查: - 有沒有遺漏的 meta tags(og:image, twitter:card 等)? - 結構化資料還能加什麼(FAQ schema, BreadcrumbList)? - 多語言 SEO 有沒有常見的錯誤模式需要注意? - Core Web Vitals 有哪些快速改善的方向? - 內部連結策略怎麼規劃? 先列出優先順序最高的 3-5 項改善建議。
參考資料

延伸閱讀#

這些是在過程中實際參考過、借鑑過的資源。

文章 為什麼重要
Apideck: Your MCP Server Is Eating Your Context Window 啟發了「隱形成本」的類比
SEO for Astro: How to Make the Fastest Framework Also the Smartest Astro SEO 實作的完整指南
JSON-LD Blog Post Example BlogPosting schema 的參考實作
Multilingual SEO and Hreflang Guide 67% 錯誤率數據的來源
How to Improve Core Web Vitals SSR 效能優化的具體方法
結論

SEO 是工程,不是玄學#

每一個決策都有原因,每一個坑都有教訓。
SSR Blog 的 SEO 不是設完 meta tag 就結束——是一個持續迭代的工程問題。

// 決策鏈

問題 1: 動態文章不在 sitemap
  → 手動補 sitemap-posts.xml

問題 2: SSR 無快取
  → 靜態頁 prerender + 動態頁 SSR

問題 3: 多語言 SEO 易出錯
  → hreflang 雙向 + x-default

驗證: Google Search Console 手動提交 + 監控

// 歸納
Astro SSR + 自動化 SEO pipeline
不漏收錄、不重複、不延遲
✦ 帶走這段