【AWS CloudFront】302がキャッシュされて画像が見れない問題とその対処法（Lambda@Edge + Nginx）

# 【AWS CloudFront】302がキャッシュされてがぞう見れない問題とその対処法（Lambda@Edge + Nginx）

CloudFront を使っていて、**302リダイレクトがキャッシュされてしまい、ユーザーが正しくページを見れない**という問題に直面したことはありませんか？

この記事では、**CloudFrontが302レスポンスをキャッシュしてしまう問題**の対処法と、それに伴う**Express.jsの副作用**や**Nginxを使った回避策**について紹介します。

---

## 🧨 発生した問題：CloudFrontが302をキャッシュしてしまう

CloudFront はデフォルトで **200以外のレスポンス（302など）もキャッシュする** ことがあります。  
これにより、一時的なリダイレクトがずっとキャッシュされてしまい、**本来表示されるべきページが見られなくなる**という事象が発生しました。

---

## 💡 解決策：302レスポンスにはキャッシュさせない

### ✅ 方法① Lambda@Edgeで `Cache-Control: no-store` を付与

CloudFrontの**オリジンレスポンス**に対してLambda@Edgeを使い、**ステータスコードが200以外のときだけ**キャッシュさせないようにします。

```javascript
exports.handler = async (event) => {
  const response = event.Records[0].cf.response;
  const statusCode = parseInt(response.status);

  if (statusCode !== 200) {
    response.headers['cache-control'] = [{
      key: 'Cache-Control',
      value: 'no-store'
    }];
  }

  return response;
};
```

> ポイント：302などの一時的リダイレクトをCloudFrontでキャッシュさせないようにする。

---

### ✅ 方法② CloudFrontのカスタムエラーページのTTLを制御

CloudFrontのエラーページ設定でも、キャッシュ期間を短く制御できます。

| 設定項目 | 値 |
|----------|----|
| 最小 TTL | `0` 秒 |
| 最大 TTL | `600` 秒 |
| デフォルト TTL | `300` 秒 |

これにより、万が一キャッシュされても **短時間で再評価される** ようになります。

---

## ⚠️ 問題再燃：Express.jsが自動で `Cache-Control` を付与してしまう

ここで新たな問題が発生。

Express.js はデフォルトで `Cache-Control: public, max-age=xxx` を自動的に付与します。  
この挙動により、302以外のレスポンスも含めて一律にキャッシュ設定され、**静的ファイルも含めてキャッシュされなくなる** という副作用が発生しました。

---

## ✅ 回避策：Nginxで強制的に `Cache-Control` ヘッダーを上書き

Express.js 側で細かく制御するのが難しかったため、**Nginxをリバースプロキシとして挟み、特定のレスポンスだけキャッシュヘッダーを外す**構成にしました。

```nginx
location / {
    proxy_pass http://localhost:3000;
    
    # 302 の場合は Cache-Control を外す
    proxy_intercept_errors on;
    add_header Cache-Control 'no-store' always;
}
```

> ※ 状況に応じて `add_header` に `if` 条件を付けたり、ルールを細かく書き分けることも可能です。

---

## 🧪 最終的な構成まとめ

```text
CloudFront
  └── Lambda@Edge（200以外のレスポンスに no-store）
        └── Nginx（Cache-Controlの強制制御）
              └── Express.js（静的ファイル配信）
```

- ✅ CloudFrontのキャッシュは必要最小限に
- ✅ Lambda@Edgeでステータスベースに振り分け
- ✅ Express.jsの意図しないキャッシュはNginxで上書き

---

## 🎯 まとめ

| 課題 | 解決策 |
|------|--------|
| CloudFrontが302をキャッシュしてしまう | Lambda@Edgeで `Cache-Control: no-store` を付与 |
| エラーページが長くキャッシュされる | TTLを最小0、最大600、デフォ300に設定 |
| Expressが自動でキャッシュを付与する | Nginxで強制的に上書きする |

---

## 👀 おわりに

CloudFrontでのキャッシュ制御は非常に強力ですが、一歩間違えると**ユーザー体験を壊してしまう**危険もあります。  
本記事のような「200以外のレスポンスに対する適切なキャッシュ制御」は、特に**認証リダイレクト**や**一時的なページ移動**が発生するサービスでは重要です。

同じようなことでハマってる人の参考になれば幸いです！

---

## 📚 参考文献

- [1] [コンテンツをキャッシュに保持する期間 (有効期限) を管理する](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist)  
  CloudFront がオブジェクトをキャッシュする期間の制御方法について。

- [1] [CloudFront がエラーをキャッシュする時間を制御する](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages-expiration.html)  
  CloudFront は 4xx・5xx レスポンスごとにキャッシュ期間（TTL）を設定可能。

- [2] [エラーレスポンスの動作を設定する - カスタムエラーレスポンス](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages-procedure.html#custom-error-pages-console)  
  エラーレスポンスをカスタマイズする方法。

- [3] [HTTP ステータスコード別のカスタムエラーページを作成する](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/creating-custom-error-pages.html)  
  CloudFrontがサポートするエラーページのステータスコード一覧。

- [4] [Lambda@Edge を使用してエッジでカスタマイズする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html)  
  CloudFront で Lambda@Edge を使う基礎。

- [5] [Lambda@Edge 関数をトリガーできる CloudFront イベント](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-cloudfront-trigger-events.html)  
  Lambda@Edge のトリガータイミングに関する解説。

- [6] [オリジンレスポンストリガーでの HTTP レスポンスを更新する](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-generating-http-responses.html#lambda-updating-http-responses)  
  `origin-response` を使って HTTP レスポンスを書き換える方法。

- [7] [Cache-Control - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Cache-Control)  
  `Cache-Control: no-store` の意味と動作（AWS公式ではない参考資料）。

- [8] [オリジンが Cache-Control を設定した場合の CloudFront キャッシュ挙動](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist)  
  `no-store` などが付与されていても CloudFront 側の最小TTL設定に影響される点。

- [9] [Lambda@Edge 関数の例: エラーステータスコードを 200 に変更](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-custom-error-static-body)  
  実践的な Lambda@Edge スニペット例。