getServerSidePropsの使い方:リクエストごとにページを生成する
getServerSidePropsでリクエストごとの値をページへ渡す方法を解説します。queryの検証、レスポンスヘッダー、SSGとの違いをコードで確認します。
getServerSidePropsでリクエストごとの値をページへ渡す方法を解説します。queryの検証、レスポンスヘッダー、SSGとの違いをコードで確認します。
対象環境と役割
Pages Routerで使う機能
Pages Routerでは pages ディレクトリを使います。App Routerの app へ同じファイルを移しても、データ取得やルーティングの規約は引き継がれません。この記事では役割を絞ったサンプルで、実行タイミングと受け渡す値を確認します。
引数・戻り値・受け渡すデータ
contextには query、params、req、res などがあります。戻り値は props、notFound、redirect のいずれかの方式を選びます。propsは閲覧者へ送られます。
コード例を動かす
pages/greeting.tsx を作成する
以下はこのファイルとして配置する例です。既存ファイルへ追記する場合は、同じ名前のexportやURLが重複しないように統合してください。
import type { GetServerSideProps, InferGetServerSidePropsType } from 'next';
type Props = { name: string; servedAt: string };
export const getServerSideProps: GetServerSideProps<Props> = async ({ query, res }) => {
const raw = query.name;
const name = typeof raw === 'string' && raw.length <= 40 ? raw : 'ゲスト';
res.setHeader('Cache-Control', 'private, no-store');
return { props: { name, servedAt: new Date().toISOString() } };
};
export default function Greeting({ name, servedAt }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return <main><h1>こんにちは、{name}さん</h1><p>{servedAt}</p></main>;
}実行結果と処理の順序
/greeting?name=Hanako を開くと名前が表示され、再読み込みすると生成時刻が変わります。名前が未指定、繰り返し指定、長すぎる場合はゲストになります。
query.name は単なる文字列とは限りません。URL入力は外部入力として検証し、文字列の型指定だけで安全だと判断しないようにします。
つまずきやすい点と使い分け
個人情報を共有キャッシュへ入れない
ログインした人に固有のレスポンスを共有キャッシュへ保存すると、別の人へ返す事故につながります。例では private, no-store を明示しました。認証済みであるかどうかの検証は別途必要です。
内部APIを経由する必要はない
同じアプリのサーバー内でDBを読めるなら、わざわざ自分のHTTP APIを呼ばず、共通のサーバー関数を利用できます。ただしその関数の秘密値をクライアントへexportしないようにします。
静的出力で使えるか
この例はリクエストごとのサーバー処理を必要とします。output: 'export' で生成した out を配信するだけのサーバーでは実行できません。Next.jsのサーバー実行環境か別のAPIを用意します。
確認課題と実務への応用
自分で値を変えて確認する
名前の省略、空文字、複数のname、41文字以上を試します。個別ユーザー向けページへ応用する場合は、URLの名前を本人確認として使わずセッションを検証してください。
開発サーバーだけでなく、本番用ビルドと公開先でも確認します。URLを直接開く場合と画面内のリンクから遷移する場合、値がない場合と不正な値の場合を分けて試すと、型だけでは防げない入力の問題が見つかります。
公式資料と関連する記事
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。