🌟

Next.jsのMiddlewareと友達になろう

2024/07/03に公開

導入

「middlewareって何?」、「重要なんだろうけど学ぶ気にならない」その人たちのための記事です。この記事を読めばmiddlewareと友達になれます。途中コードもありますが、必ず手を動かして、コードを写して読みましょう。「このコード使わなそう」と思っても書きましょう。いつか、そのコードと出会う日が来るでしょう。

middlewareとは

httpのrequestが終わる前に実行される。requestの内容によって、responseやrequest,response headersを修正する。middlewareは、cacheされる前、routeがマッチする前に実行される。

メリット

middlewareを使うことで、パフォーマンス、セキュリティ、ユーザ体験(その製品を使った時の満足度)が上がる

middlewareが効果的な場面

場面 情報
認証機能(auth) 他のページやapiルートにアクセスする前にユーザ情報やセッションを確認
server-sideリダイレクト ユーザの役割など、状況に応じてリダイレクトするとき
パスの書き換え requestに基づいてページやAPIルートを動的に書き換えるとき
Bot Detection リソースを保護する
loggingと分析 ページやAPIルートに進む前に、requestデータを分析する

middlewareが効果的ではない場面

場面 情報
複雑なデータのfetch middlewareは直接的なデータのfetchのために作られていない。そのような処理は、route handlersやserver utilitiesで行う
重い処理 middlewareは軽くてレスポンスが素早いものであるべき。重い処理は、route handlersで行うべき
広範囲なセッション管理 middlewareは基本的なセッション管理はできるが、広範囲な管理は、認証サービスやroute handlersで管理するべき
データベースの操作 データベースの操作は、route handlersやserver utilitiesが行うべき

Matching Paths

middlewareは、すべてのルートに対して呼び出される(requestが終わる前に実行されるから)。ただ、matchersを使えば、特定のルートに対して実行させることができる。

middleware.ts
export const config={
matcher:['/about/:path','/dashboard/:path']
}

以下の例は、api,_next/static(staticファイル),_next/image(image optimizationファイル)、favicon.ico(faviconファイル)以外のファイルに対して、middlewareを実行させるコードである。

middleware.ts
export const config={
matcher:[
'/((?!api|_next/static|_next/image|favicon.ico).*)',
]
}

条件文

middleware.ts
import {NextResponse} from 'next/server'
import type {NextRequest} from 'next/server'

export function middleware(request:NextRequest){
if(request.nextUrl.pathname.startsWith('/about')){
return NextResponse.rewrite(new URL('/about-2',request.url))
}
if(request.nextUrl.pathname.startsWith('/dashboard')){
return NextResponse.rewrite(new URL('/dashboard/user',request.url))
}
}

middlewareでcookiesを使う

NextRequestが出てきますが、その説明は以下の記事を見てください
https://zenn.dev/maiamitorio/articles/223b60ddbc1a12

middleware.ts
import {NextResponse} from 'next/server'
import type {NextRequest} from 'next/server'

export function middleware(request:NextRequest){
let cookie=request.cookies.get('nextjs')
console.log(cookie) // {name:'nextjs',value:'fast',Path:'/'}
console.log(allCookies) //[{name:'nextjs',value:'fast'}]

request.cookies.has('nextjs') //true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') //false

const response=NextResponse.next()
response.cookies.set('vercel','fast')
response.cookies.set({
  name:'vercel',
value:'fast',
path:'/',
})
cookie=response.cookie.get('vercel')
console.log(cookie) //{name:'vercel',value:'fast',Path:'/'}
return response
}

Headersを設定する

middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request:NextRequest){
const requestHeaders=new Headers(request.headers)
//headerをコピーして、新しいheaderを設定
requestHeaders.set('x-hello-from-middleware1','hello')

//NextResponseのrewriteを使用してheaderを書き換えることもできる
const response=NextResponse.next({
request:{
headers:requestHeaders,
}
})
response.headers.set('x-hello-from-middleware2','hello')
return response
}

注意事項として、重いheaderは書かない。middlewareの役割に反するから。

まとめ

middlewareは、軽くて素早い処理に使う
重い処理は、route handlersやserver utilitiesに任せるべき

参考文献
https://nextjs.org/docs/app/building-your-application/routing/middleware#nextresponse

Discussion