HTTPキャッシュ入門：基本から応用まで

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/1190fa95-c6f7-13c1-2898-afcd6dc28cef.png)](https://leapcell.io/?lc_t=q_httpcache)

## HTTPキャッシュとは

HTTPキャッシュは、サーバーの負荷を軽減し、クライアントの応答時間を短縮し、ネットワーク帯域幅を節約することで、Webパフォーマンスを向上させる技術です。HTTPキャッシュには、**強制キャッシュ**と**協調キャッシュ**の2種類があります。

## 強制キャッシュ

強制キャッシュでは、クライアントが指定された期間内にローカルにキャッシュされたリソースを直接使用できるようにします。この場合、サーバーへのリクエストを送信する必要はありません。強制キャッシュは、サーバーによって指定されるレスポンスヘッダー、主に**Cache-Control**と**Expires**フィールドによって制御されます。

### Cache-Control

**Cache-Control**は、最大有効期間（`max-age`）、キャッシュの共有可否（`public`または`private`）、および変更の許可可否（`no-cache`または`no-store`）を指定する汎用ヘッダーです。

例：

```yaml
Cache-Control: max-age=3600
```

上記は、リソースが3600秒間有効であり、キャッシュ可能であることを示しています。

### Expires

**Expires**は、キャッシュの有効期限を絶対的な時間で指定する廃止予定のフィールドです。

例：

```yaml
Expires: Wed, 23 Aug 2024 03:36:26 GMT
```

これは、リソースが2024年8月23日午前3時36分26秒に期限切れになることを意味します。  
**Cache-Control**と**Expires**の両方が存在する場合は、**Cache-Control**が優先されます。

## 協調キャッシュ

協調キャッシュでは、クライアントがリソースが更新されているかどうかをサーバーに確認する必要があります。更新されていない場合、サーバーは`304`ステータスコードと空のレスポンスボディを返し、クライアントはローカルキャッシュを引き続き使用できます。更新されている場合、サーバーは`200`ステータスコードと新しいリソースを返し、ローカルキャッシュを置き換えます。協調キャッシュは、主に**Last-Modified/If-Modified-Since**と**ETag/If-None-Match**ヘッダーを利用します。

### Last-Modified/If-Modified-Since

**Last-Modified**は、リソースの最終更新時刻を示すサーバー側のフィールドです。

例：

```yaml
Last-Modified: Tue, 22 Aug 2024 02:36:26 GMT
```

これは、リソースが2024年8月22日午前2時36分26秒に最終更新されたことを示しています。

**If-Modified-Since**は、リソースを最後に取得した時刻を示すクライアント側のフィールドです。

例：

```yaml
If-Modified-Since: Tue, 22 Aug 2024 02:36:26 GMT
```

これは、クライアントがリソースを2024年8月22日午前2時36分26秒に取得したことを示しています。  
両方のタイムスタンプが等しい、または**Last-Modified**がより古い場合、リソースは更新されていません。**Last-Modified**が後の場合、リソースは更新されています。

### ETag/If-None-Match

**ETag**は、リソースの一意の識別子を表すサーバー側のフィールドです。

例：

```yaml
ETag: '5d3a9f6d-1f86'
```

これは、リソースの識別子が`"5d3a9f6d-1f86"`であることを示しています。

**If-None-Match**は、リソースの期待される識別子を示すクライアント側のフィールドです。

例：

```yaml
If-None-Match: '5d3a9f6d-1f86'
```

これは、クライアントがリソース識別子として`"5d3a9f6d-1f86"`を期待していることを示しています。  
両方の値が一致する場合、リソースは更新されていません。不一致の場合、リソースは更新されています。

## HTTPキャッシュのベストプラクティス

協調キャッシュと強制キャッシュを組み合わせることで、不要なネットワークリクエストを効果的に削減しつつ、常に最新のコンテンツをユーザーに提供できます。

### 一般的なアプローチ：

**強制キャッシュ**：CSSやJS、画像などの静的リソースには長いキャッシュ期間を設定します。これにより、ブラウザはサーバーに問い合わせることなくローカルストレージからリソースを直接取得できます。

**協調キャッシュ**：変更される可能性のあるリソースには協調キャッシュを使用します。ブラウザはリソースが変更されたかどうかをサーバーに確認します。変更されていない場合、サーバーは`304 Not Modified`レスポンスを返し、ブラウザはローカルキャッシュを使用します。リソースが変更された場合、サーバーは`200 OK`と更新されたリソースを返します。

### 実装例：

Express.jsをバックエンドフレームワークとして使用する場合：

```javascript
const express = require('express');
const app = express();

// 強制キャッシュ：静的リソースにキャッシュを設定
app.use(
  '/static',
  express.static('public', {
    maxAge: '1y', // キャッシュ期間は1年
  })
);

// 協調キャッシュ：ETagとLast-Modifiedを使用
app.get('/resource', (req, res) => {
  const content = '...'; // リソースの内容を取得
  const etag = generateETag(content); // ETagを生成

  // If-None-Matchヘッダーを確認
  if (req.headers['if-none-match'] === etag) {
    res.status(304).end(); // リソースが変更されていない場合、304を返す
  } else {
    res.setHeader('ETag', etag);
    res.send(content); // リソースが変更されている場合、新しい内容を返す
  }
});

function generateETag(content) {
  return require('crypto').createHash('md5').update(content).digest('hex');
}

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
```

## 注意事項

- **バージョン管理**：強制キャッシュの効果を最大化するために、リソースURLにバージョン情報を含めます。例：`/static/js/main.2024082301.js`。リソースを更新する際には、バージョン番号を変更して、ユーザーが常に最新バージョンを取得できるようにします。

- **協調キャッシュのコスト**：協調キャッシュは不要なデータ転送を削減しますが、ネットワークの往復が必要です。ほとんど変更されないリソースには、強制キャッシュのほうが効率的な場合があります。

---

### [私たちはLeapcell、バックエンド・プロジェクトのホスティングの最適解です](https://leapcell.io/?lc_t=q_httpcache)

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/c39939f3-4bdc-e186-3bd8-22ae16ba0553.png)](https://leapcell.io/?lc_t=q_httpcache)

[Leapcell](https://leapcell.io/?lc_t=q_httpcache)は、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです：

**複数言語サポート**

- Node.js、Python、Go、Rustで開発できます。

**無制限のプロジェクトデプロイ**

- 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

**比類のないコスト効率**

- 使用量に応じた支払い、アイドル時間は課金されません。
- 例: $25で6.94Mリクエスト、平均応答時間60ms。

**洗練された開発者体験**

- 直感的なUIで簡単に設定できます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

**簡単なスケーラビリティと高パフォーマンス**

- 高い同時実行性を容易に処理するためのオートスケーリング。
- ゼロ運用オーバーヘッド — 構築に集中できます。

[ドキュメントで詳細を確認！](https://docs.leapcell.io/)

[![Try Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/b0179f01-81a4-9ff2-b345-65961d0b9d2a.png)](https://leapcell.io/?lc_t=q_httpcache)

Xでフォローする：[@LeapcellHQ](https://x.com/LeapcellHQ)

---

[ブログでこの記事を読む](https://leapcell.io/blog/http-caching-101)