SSR
SSR 在請求時由伺服器回傳完整 HTML,讓爬蟲與使用者更快看到內容,提升可索引性與首屏體感。
定義
SSR(Server-Side Rendering)指每次請求時,由伺服器把 React 等框架渲染成 HTML 後再回傳。它能讓『內容』與『meta/schema』在第一時間就可讀,對 JavaScript SEO 非常友善。
為什麼重要
- 更快提供可索引內容,不必等爬蟲執行 JavaScript
- 首屏更穩:內容先到,互動再 hydration,改善 LCP
- 適合需要即時資料或個人化內容的頁面(如用戶儀表板)
- 社群分享正確:OG tags 在初始 HTML,Facebook/Twitter 可正確抓取
- 支援 AI 引擎索引:ChatGPT/Perplexity 的爬蟲渲染能力有限
- 降低 Googlebot render queue 依賴:頁面立即可讀
- 提供一致的 SEO 體驗:不論用戶或爬蟲都看到相同內容
怎麼做(實作重點)
- 確保 SSR 輸出包含完整 head:title/description/canonical/hreflang/schema
- 避免 hydration mismatch:保持初始 HTML 與 CSR 一致,否則 React 會報錯
- 用 prerender/SSG 承接可靜態化的頁面,降低 SSR 伺服器成本
- 設定快取策略:對相同請求使用 stale-while-revalidate 減少渲染次數
- 監控 TTFB:SSR 增加伺服器處理時間,需優化資料取得速度
- 處理錯誤情況:確保 404/500 頁面也正確 SSR 並回傳對應狀態碼
- 使用 streaming SSR:React 18+ 支援逐步傳送 HTML,改善首屏體驗
範例
typescript
// pages/product/[id].tsx
import { GetServerSideProps } from 'next';
import Head from 'next/head';
interface ProductProps {
product: { id: string; name: string; price: number };
}
export default function ProductPage({ product }: ProductProps) {
return (
<>
<Head>
<title>{product.name} | My Store</title>
<meta name="description" content={`Buy ${product.name} for ${product.price}`} />
<link rel="canonical" href={`https://mystore.com/product/${product.id}`} />
</Head>
<h1>{product.name}</h1>
<p>Price: ${product.price}</p>
</>
);
}
export const getServerSideProps: GetServerSideProps = async ({ params, res }) => {
const product = await fetchProduct(params?.id as string);
if (!product) {
return { notFound: true }; // 回傳 404
}
// 設定快取(CDN 可用)
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');
return { props: { product } };
};typescript
// app/routes/blog.$slug.tsx
import { json, LoaderFunctionArgs, MetaFunction } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
export const loader = async ({ params }: LoaderFunctionArgs) => {
const post = await getPost(params.slug!);
if (!post) {
throw new Response('Not Found', { status: 404 });
}
return json(post, {
headers: { 'Cache-Control': 's-maxage=3600' }
});
};
export const meta: MetaFunction<typeof loader> = ({ data }) => {
if (!data) return [{ title: 'Not Found' }];
return [
{ title: data.title },
{ name: 'description', content: data.excerpt },
{ property: 'og:title', content: data.title },
];
};
export default function BlogPost() {
const post = useLoaderData<typeof loader>();
return <article><h1>{post.title}</h1><div>{post.content}</div></article>;
}相關連結
常見問題
關於這個詞彙的常見問答。