Vercel でホスティングしてる Next.js に Cloudflare の Cache を適用する
現状 Cloudflare ダッシュボードの設定でどうにかなるわけではないので worker を経由する必要があるぽい。
Cloudflare Worker にこれを設定して
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const varyKeys = [
'RSC',
'Next-Router-State-Tree',
'Next-Router-Prefetch',
'Accept-Encoding',
]
// append these headers to the searchParams in order to distinguish requests with them or not
for(const key of varyKeys) {
if (request.headers.has(key) ) {
url.searchParams.set(key, request.headers.get(key))
}
}
const rewrittenRequest = new Request(url, request);
let cache = true
// Do not cache routes starting with `/api`
if(url.pathname.startsWith('/api')) {
cache = false;
}
let response = await fetch(rewrittenRequest, {
cf: {
cacheEverything: cache,
// only cache 2xx status codes
cacheTtlByStatus: { 404: 1, "500-599": 0, "300-399": 1 }
},
});
// Reconstruct the Response object to make its headers mutable.
response = new Response(response.body, response);
return response;
},
};
Next.js の middleware にこれを設定するといいらしい
import { NextResponse } from 'next/server';
import { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const url = new URL(request.nextUrl);
// Check for vary headers appended by cloudfare worker
const varyKeys = [
'RSC',
'Next-Router-State-Tree',
'Next-Router-Prefetch',
'Accept-Encoding',
];
let varyFound = false;
// remove these headers from the URL
for (const key of varyKeys) {
if (url.searchParams.has(key)) {
url.searchParams.delete(key);
varyFound = true;
}
}
if (varyFound) {
return NextResponse.rewrite(url);
}
return NextResponse.next();
}
export const config = {
// exclude api, images & static paths (_next/static & _next/image)
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)',
],
};
Cloudflare でドメインをとって proxied にしていれば cache されると思っていた.....
よくよく見てみると cf-cache-status: DYNAMIC
になっていたため Cache を効くようにに変更してみる。
この辺を見て設定する
curl <URL> -I
で確かめる
last-modified: Sun, 03 Mar 2024 15:24:17 GMT
cf-cache-status: HIT
age: 73
できてる
Link コンポーネントで遷移する部分の挙動がおかしい。
Link で SPA 的な挙動をするときは問題ないが、target="_blank"
で開くと RSC がそのまま表示される。
どうやら既知の問題らしく Next.js の issue で議論されていた。Cloudflare community のほうでは全く動きなしだった。
Vary
header に基づいて CDN が cache をコントロールすべきだと理由で close されている。
Vary
header は同じ URL でも Vary が異なるものであれば別物として扱うもの
とりあえず Vary
header をみるように Cloudfalre Cache Rules を設定できるか調べる。
Ok, after an intense testing, i found out that cloudfare CDN does not respect the Vary header to properly cache different responses types.
to quote from Cloudfare docs :vary — Cloudflare does not consider vary values in caching decisions. Nevertheless, vary values are respected when Vary for images is configured and when the vary header is vary: accept-encoding.
むりだったw
これをやってもさらに microcms からの更新で cache purge の設定も必要なのでサクッとできなさそうなのでいったんここで調べるのはやめる