🚚

Next.js で SSR/SSG したページに Cache-Control などのヘッダを設定する

1 min read

Next.js には強力な Incremental Static Regeneration がありますが、Vercel 以外にホストしている場合は使うことができません。そのとき、Cache-ControlSurrogate-Control ヘッダを用いて Fastly のような CDN にキャッシュを持たせたくなります。
このヘッダの持たせ方に少しクセがあったので備忘録的に書きます。

例えば、/articles/[id] にヘッダを持たせたいとします。

方法1. next.config.js で設定

next.config.jsheaders で設定する方法です。

next.config.js
const cacheHeaders = [
  {
    key: 'Cache-Control',
    value: 'max-age=0',
  },
  {
    key: 'Surrogate-Control',
    value: 'public, max-age=300',
  },
];
module.exports = {
  {
    source: '/articles/:id*',
    headers: cacheHeaders,
  },
  {
    // Client Routing で SSR するページに遷移したとき
    source: '/_next/data/:hash/articles/:id*',
    headers: cacheHeaders,
  },
};

Next.js における SSR は HTML と json の2パターンがあり、直接 SSR ページを開いた場合はレンダリング結果の HTML、他のページから next/linknext/router で遷移した場合は props が json として返されます。

単純に /articles/:id* と指定するだけでは、HTML にしかヘッダが設定されません。json は /_next/data/${hash}/articles/search/${id}.json?id=${id} のような path で配信されるため、/_next/data/:hash/articles/:id* と指定します。

方法2. getServerSideProps で設定

これは SSR 限定の方法ですが、getServerSideProps でレスポンスを書き換える方法もあります。

/pages/articles/[id].tsx
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
  context.res.setHeader('Cache-Control', 'max-age=0');
  context.res.setHeader('Surrogate-Control', 'public, max-age=300');

  return {
    props: { ... },
  };
};

GetServerSidePropsContext が持つ res オブジェクトに対する操作は、HTML と json の両方に反映されます。

おわりに

SSR 以外の場合にもっとシンプルに設定する方法がある気がしていて、もしあればおしえてください。