Next.js(App router)のmiddleware機能を利用して、特定ページにアクセスされたら404(Page Not Found)になるよう設定してみます。Cloudflareで404レスポンスを返すには別途対応が必要です
動作確認環境
Next.js: 14.2.3
Next.jsのmiddleware機能を利用して、ルーティングを設定してみます
特定のページにアクセスがあった場合に、非表示ページとして404を偽装したい時などに便利です
middleware.ts
は app
ディレクトリと同じ階層に配置します
src
├── middleware.ts
└── app/
├── page.tsx
└── error/
└── 404/
└── page.tsx
例として /minaide
とそれ以下の階層にアクセスがあった場合、404にルーティングをしたい場合は以下のように記述します
/error/404
に配置する404ページを別途設置する必要がありますが rewrite
メソッドで実現可能です 🎉
import { NextRequest } from 'next/server'
export const middleware = async (req: NextRequest) => {
if (req.nextUrl.pathname.startsWith('/minaide')) {
return NextResponse.rewrite(`${req.nextUrl.origin}/error/404`, { status: 404 })
}
return NextResponse.next()
}
NextResponse.next()
は、リクエスト通りに処理を続けることを示します
/error/404 を別途設置したくない場合
以下のCloudflare問題と同じ対応を取ることで、回避できます (若干ゴリ押しですが)
Cloudflareにデプロイした場合は、相性問題なのか404として返答がされない場合があります (ページは404が表示される)
ローカル上でビルドした場合は、問題なく404が返却されます
curl -I https://example.com/minaide
HTTP/2 200
date: Mon, 20 May 2024 14:08:45 GMT
content-type: text/html; charset=utf-8
...
ちょっと気持ち悪いので、これを修正したい場合は、新たに NextResponse
を生成することで対応できます
import { NextResponse, NextRequest } from 'next/server'
export const middleware = async (req: NextRequest) => {
if (req.nextUrl.pathname.startsWith('/minaide')) {
const body = await (async () => {
try {
return await (await fetch(`${req.nextUrl.origin}/404`)).text()
} catch {
return '<h1>404 Not Found</h1>'
}
})()
const res = new NextResponse(body, {
status: 404,
headers: {
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=0, must-revalidate',
'Content-Type': 'text/html; charset=utf8',
'X-Content-Type-Options': 'nosniff',
'X-Matched-Path': '/404',
'X-Robots-Tag': 'noindex',
},
})
return res
}
return NextResponse.next()
}
404ページの取得などが若干ゴリ押しではありますが、これでCloudflareでも404が返却されるようになります 🎉
HTTP/2 404
date: Mon, 20 May 2024 14:20:56 GMT
content-type: text/html; charset=utf8
...
おわりに
環境変数と組み合わせれば、StagingとProductionで異なるルーティングを実現することも可能です 🐶