定義
フレームワークの内蔵画像最適化が使えない状況で、大きな元画像を画面に必要な小さいサイズ・軽いフォーマットにサーバーが代わりに変換して返したいときに作る中間サーバー(エンドポイント)だ。ブラウザは元画像の代わりに、このサーバーがリサイズ・変換した画像を受け取る。
正確に言えば、サーバー画像プロキシはクライアントが要求した表示サイズに合わせて upstream(元画像がある対象サーバー)画像を fetch → リサイズ・フォーマット変換(例:WebP、容量の小さいウェブ画像フォーマット)→ 応答する HTTP エンドポイントだ。このようにフォーマット・サイズを変えることをトランスコーディングという。CDN edge キャッシュ(ユーザーに近いサーバーノードに結果を保存して再利用)と関数インメモリ LRU(Least Recently Used、長く使っていない項目から捨てるメモリキャッシュ)を重ねて使い、miss(キャッシュになく元画像を新たに処理する場合)時にはストリーミング tee(一つのデータストリームを二つに分け、一方はすぐ応答、一方はキャッシュに保存)で TTFB(Time To First Byte、リクエスト後に最初のバイトが届くまでの時間)を減らす。
なぜ必要か
フレームワークの images.unoptimized: true 設定だと、<Image> が元の PNG/JPEG をそのまま返すことがある。カルーセルのサムネイルのように画面上で小さい画像は、サーバーで 336〜672px の WebP に変えるだけで転送バイトが数十〜数百倍減り、LCP(Largest Contentful Paint、画面で最も大きいコンテンツが描画される時点の指標)のボトルネックが「画像ダウンロード」から「レンダー」に移ることが多い。パフォーマンス A/B では、転送バイトが localhost の LCP よりも再現可能な headline(代表指標)になる。
動作原理
SSRF は Server-Side Request Forgery の略で、攻撃者が url パラメータに内部ネットワークのアドレスを入れ、サーバーに代わりにリクエストさせる脆弱性だ。allowlist(許可されたホストのリスト)でこれを防ぐ。
| 層 | 役割 |
|---|---|
CDN (s-maxage) | cold start 以降 durable、エッジ配信 |
| モジュール LRU | warm lambda での反復 hit、ephemeral |
クライアントでは loader の代わりに src をプロキシ URL に直接置き換える方が、unoptimized 環境では決定的だ。<link rel="preload"> の href も同じ URL でないと二重ダウンロードを防げない。
実務適用
wは固定集合のみ許可(それ以外は 400) — DoS・キャッシュキー爆発を防止。- Node runtime + sharp(または同等)。
- MSW/E2E: mock URL がルートに到達できない場合、テスト環境でプロキシを迂回する分岐を設ける。
トレードオフ
| 選択 | 利得 | コスト |
|---|---|---|
| 自前プロキシ | unoptimized の迂回、フォーマット・品質の制御 | サーバー CPU・SSRF 表面 |
toBuffer() 後に応答 | 実装がシンプル | miss の TTFB 増加 |
| ストリーミング tee | 最初のバイトが速い | ストリーム途中失敗時のキャッシュスキップ処理が必要 |
| WebP q60 | 小さいバイト | 品質・アーティファクト — 用途別に調整 |
使ってはいけない場合
- すでに CDN・画像 CDN が最適化・キャッシュを提供しているのに、重複したプロキシだけを追加する。
- allowlist なしで任意 URL を fetch する。
よくある間違い
- preload は元画像、
img srcはプロキシ — preload が無効・二重リクエスト。 - キャッシュキーに presigned URL 全体を含める — 署名ローテーションごとに miss。
- localhost trace の LCP だけを headline にする — 実配備の CDN の利得はもっと大きい。
関連概念
- ssrf-url-fetch-proxy-guard — fetch 前のセキュリティ
- lqip-blur-placeholder-ssr — blur placeholder(LCP 指標とは別)
- resource-priority — preload・fetchpriority
- largest-contentful-paint — LCP ボトルネックの移行