あかね
「middleware効かない」はキャッシュのせいだった話
2026年03月18日
要約を生成中...
はじめに
なんか知らんけど直したのに反映されない😇ログインしているのに弾かれる😇こういう現象、経験ある方も多いと思います。
CTOがキャッシュを恐れていて、最初は「キャッシュって便利なものやろ?なんで恐れてるんやろ?」って思っていたのですが、これは私の知識不足故の疑問で、いろんなバグと格闘してキャッシュの暴走を体感しつつキャッシュされるレイヤーを理解することで戦えるようになってきました。
去年のことですが経験したキャッシュの暴走を例にしつつ書いてみます。
キャッシュの本質
キャッシュって「速くするためのもの」って思われがちなんですが、ちょっと違う側面も持っていて、結構重大な事実だと思うのが、どこで処理が止まるかを決める仕組みというところです。
キャッシュが返るとそれより先の処理に進まないんです。
本来届くはずの場所にリクエストが届かず、勝手に手前でレスポンスが返されてしまう。
これを私はキャッシュの暴走と呼んでいます。
キャッシュは1箇所じゃない
これが最初わからなくてはぁ?ってなってたんですが、Webアプリって、こんな構造になってます。
Browser
↓
CDN(CloudFrontやVercel Edgeなど)
↓
Next.js(middleware / fetch)
↓
Rails API
↓
DB キャッシュはこの中のいろんな場所にあります。
例えば、CDNのキャッシュが返るとDBのデータと違うデータを参照してブラウザに表示されるとか、middlewareの処理が走らないということが起こります(そうです、起こりました🤯)
クライアントにもキャッシュはある(SWR)
見落としがちなんですが、キャッシュはサーバー側だけじゃありません。
例えば我らがSWRですね。
const { data } = useSWR("/api/products", fetcher);これのdataはどこでキャッシュされているかというと、ブラウザ(クライアント側)です!
つまりSWRのキャッシュをレイヤーでいうとこうなります。
Browser(SWRキャッシュ)
↓
CDN
↓
Next.js
↓
Rails
↓
DBSWRで起きがちなこと
APIは正しい値を返しているのにUIが変わらない
mutateしないと更新されない
これも本質は同じで、キャッシュされたデータを見ているだけです。
これも暴走との格闘経験ありますw
SSR(サーバーサイドレンダリング)で取得したデータをUIに表示していて、mutateしているのに更新されないって騒いでました。(結構ヤバめのバグですね☺️)
SSRで取得したデータをSWRのfallbackに渡し、あくまでクライアントサイドで表示するのはSWRのキャッシュにすることで解決でした。
SSRでデータ持ってきたから最新のはず!なのにSWRが古いキャッシュを被せてきて画面が先祖返りする……あの絶望感w
分かれば当たり前すぎるんですがハマるまで気づかなかったですw
キャッシュが原因で「処理に到達しない」ことがある
これが一番やばいポイントです。
コードは正しいのに、そもそもそのコードが実行されていない。
だいたいconsole.log仕込んでるのに表示されない😇で、ここに処理到達していないことがわかりキャッシュかぁ、、、ってなりました。
実際にハマった例:middlewareが効かない
あるとき、認証ガードが効かない問題にハマりました。
「ログインしていないのに /dashboard にアクセスできてしまう」
本来は middlewareでaccess_tokenをチェックして、未ログインならリダイレクトするという実装なんです。
export function middleware(req: NextRequest) {
const token = req.cookies.get("access_token"); if (!token) {
return NextResponse.redirect(new URL("/login", req.url));
}
}ロジック的には正しいはずなのに、なぜか突破される。
log仕込んでも表示されない、なんでや、、、絶望、、、みたいな流れですね。
実際に起きていたこと
問題はコードではなく、キャッシュレイヤーにありました。
① 初回アクセス(未ログイン)
Browser
↓
CDN
↓
Next.js(middleware実行)
↓
HTML生成(未ログイン状態) このとき生成されたHTMLが、CDNにキャッシュされます。
② 次のアクセス(ログイン後など)
Browser(cookieあり)
↓
CDN(キャッシュHIT)
↓
HTML返却(終了) ここで重要なのは、CDNがレスポンスを返した時点で処理が終わるということ。
つまり、Next.js にリクエストが届かないのでmiddlewareが実行されないということです。。
なぜこうなるのか
CDNは、リクエストごとにロジックを評価しているわけではありません。
「このURLのレスポンスはこれ」とキャッシュしているだけです。
そしてキャッシュを返すかどうかの判断基準は特にないので
Cookieを見ていない
認証状態も考慮していない
HTTPレスポンスヘッダー(Cache-Control)に従う
つまり、ユーザーごとに結果が変わるのに、同じレスポンスを返してしまう状態になっていました🙈
解決方法
HTMLをキャッシュさせないようにします。
export const dynamic = "force-dynamic";これによって、
Cache-Control: no-store が付与される
CDNがHTMLをキャッシュしなくなる
毎回Next.jsまでリクエストが届く
middlewareが確実に実行される
ということで解決しました。
middleware特有の問題ではない
この問題、middlewareに限った話ではなく、同じことは他のレイヤーでも起きます。
ブラウザキャッシュ(SWR) → UIが更新されない
CDNキャッシュ → middlewareに到達しない
APIキャッシュ → DB更新しても反映されない
共通しているのはキャッシュされた時点で、その先の処理は一切実行されないということです。
本当に厄介です。レスポンスが早いのは嬉しいけど過去のデータになっては問題が起こります😭
Next.jsではなくHTTPの話
export const dynamic = "force-dynamic";これ、Next.jsの設定に見えるんですがやってることはシンプルで、「このレスポンスはキャッシュするな」ってHTTPで指示しているだけです。
書き方はフレームワークにより色々ですが!
動作環境
Next.js(App Router / middleware使用)
Amplify(CDN + Hosting)
Rails API
SWR
まとめ
繰り返しになりますがキャッシュを理解するというのは、速くすることだけではなく「どこで処理が止まるか」を理解することです。
「middlewareが効かない」のではなく、「middlewareに到達していなかった」
地道にデバックするしかないですし、logが出ないというのはキャッシュの仕組みを理解していないと困惑しかないと思うので、頭の片隅にでも置いておいていただけると良いかと思います!
AIはコード単体(middleware.ts)の正解は教えてくれるけど、インフラ(CDN)を含めた立体的な構造までは見抜けないからこそ、自分の手でlogを仕込んで、物理的な『到達範囲』を確認する力が試されるのかなと思います!(知らんけど多分)
おわりに
キャッシュでハマる時ってほんと意味わからんって感じで、あぁぁぁぁぁぁあってなりますw
DBのデータは正しいのに表示が変!なんでか知らんけど思った挙動にならん!何が起きているぅぅ!!!????みたいな。
DBのデータ見たいのに見れてない → キャッシュが暴走してる!!!!
って発想になれたらあとはどこまで処理いってる?かを突き止めていけば、どこのキャッシュをどうしたらいいか戦略を考えるだけなのでもうほぼ解決です🥳
キャッシュとは仲良く、うまく付き合っていきたいものです🪭

