...

WordPressのJSONレスポンス:読み込み時間の過小評価

WordPressのJSONレスポンスは、ページがどれだけ早く構築されるかを決定することが多い。 ペイロード, 遅いクエリとキャッシュ不足がTTFBとLCPを増加させます。WordPressのJSONレスポンスを大幅に削減し、リクエストを高速化し、TTFBとLCPを大幅に改善する方法を紹介します。 ローディング時間 機能性を失うことなく。.

中心点

  • ペイロード 減らす:フィールドを限定し、終点を合理化する。.
  • クエリ バンドル:N+1を避け、オプションを整理する。.
  • キャッシング レイヤーに保存されます:ETag、オブジェクトキャッシュ、ブラウザキャッシュ。.
  • 輸送 最適化する:HTTP/3、Brotli、ヘッダを正しく設定する。.
  • 見本市 そして行動する:TTFB、LCP、クエリータイムを追跡する。.

JSONレスポンスが読み込み時間を遅くする理由

wp/v2/postsのような標準的なエンドポイントは、多くのプロジェクトが決して必要としない完全な投稿オブジェクトを提供することが多い。 データ量 不必要に肥大化する。20の投稿はすぐに100KB以上のJSONになり、ブラウザはまずそれを解析しなければならない。N+1クエリーパターンは、店舗や大規模ブログで発生する。WordPressはまず投稿を読み込み、次に各投稿のメタフィールドを取得する。圧縮がない場合、あるいはGzipしか使用されていない場合、転送時間も増加する。そのため、私は次の3つを優先している。 回答, より少ないクエリ、積極的なキャッシュ。.

高速APIの基盤としてのホスティング

コードを最適化する前に、私は TTFB ホスティングの場合:高いレイテンシーがAPIの利益を奪う。NVMe SSD、HTTP/3、オブジェクトキャッシュがPHPとデータベースを圧迫しない。高速なスタックは、特に多くのGETリクエストのレスポンスタイムを顕著に短縮します。より深く理解するために ロード時間分析 をRESTエンドポイントに焦点をあてて作成しました。この表は、典型的な測定ポイントを示したもので、私が 決定 に会う。

ホスティングプロバイダー TTFB API応答時間 価格 ヒント
webhoster.de <200ミリ秒 <120ミリ秒 2,99ユーロから 速い NVMe、HTTP/3、Redisのおかげで
その他 >500ミリ秒 >500ミリ秒 変数 ゆっくりと APIロード付き

データベースクエリを解除する

N+1クエリーは ランタイム そのため、各投稿ごとにメタデータを取得するのではなく、クエリを要約しています。1つのget_posts()リクエストでmeta_queryを使うことで、ラウンドトリップを減らしています。また、wp_optionsのクリーンアップも行っています。大きなautoloadエントリ(autoload=’yes‘)は、APIコールを含め、すべてのページを長くしてしまいます。WooCommerceでは、注文クエリがより速く実行されるようにHPOSに切り替えています。WordPressが必要とする個々のステップが少なければ少ないほど、より効率的です。 API.

// 悪い:N+1
$posts = get_posts();
foreach ($posts as $posts) { $meta = get_post_meta($post->ID 'custom_field'); // N+1
    $meta = get_post_meta($post->ID, 'custom_field');
}

// Good: クエリ
$posts = get_posts([
    'meta_query' => [
        ['key' => 'custom_field', 'compare' => 'EXISTS' ]。
    ]
]);

的を絞った方法でペイロードを減らす

私は、不要なフィールドを 応答 で、_fieldsパラメータを一貫して使用します:/wp/v2/posts?_fields=id,title,slug。これにより、転送サイズがすぐに半分になることがよくあります。また、per_pageを防御的に設定し、使用していないエンドポイント(例:/wp/v2/comments)を非アクティブにし、エンベッドが必要ない場合は_embedを避けています。インターフェイスが実際にレンダリングするデータだけを自分のエンドポイントに提供します。保存されたプロパティはすべて ミリ秒.

JSONレスポンスのキャッシュ

私はいくつかのキャッシュレイヤーを組み合わせている:ブラウザ用のETagとLast-Modified、ブラウザ用の オブジェクトキャッシュ サーバ上のRedisのようなものと、キャッシュ制御による適度なTTL。これは、データが変更されていない場合、WordPressがレスポンスを再計算する必要がないことを意味します。GETエンドポイントでは、stale-while-revalidateを使用する価値があり、サーバーがバックグラウンドで更新している間、ユーザーはすぐに何かを得ることができる。Brotli圧縮はしばしばGzipよりもJSONを圧縮する。 トランスミッション 再び加速した。.

add_filter('rest_post_dispatch', function ($response, $server, $request) {
    if ($request->get_method() === 'GET') {
        $data = $response->get_data();
        $etag = '"' . md5(wp_json_encode($data)) . '"';
        $response->header('ETag', $etag);
        $response->header('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
    }
    return $response;
}, 10, 3);

HTTPヘッダーとトランスポートの微調整

正しいヘッダーは多くの時間を費やすので、私は次のように設定した。 可変Accept-EncodingとDate。HTTP/3とTLSの再開を有効にして、ハンドシェイクの待ち時間を少なくする。CORSで保護されたエンドポイントについては、Access-Control-Max-Ageを定義して、プリフライトがキャッシュに残るようにしている。長いキープアライブ間隔は、同じ接続で複数のAPIコールを送信するのに役立つ。実用的な詳細を含むコンパクトな概要は、以下を参照されたい。 REST APIガイド, と呼んでいる。 チェックリスト を使う。

フロントエンドの統合:意味があるときにロードする

JSONのロードは「後で」であって、「多分後で」ではない。 フェッチ の後。私は、ブロックスクリプトをdeferとしてマークし、最初のペイントが早く行われるようにセグメントバンドルにしている。本当に重要なファイルにはpreloadを設定し、prefetchは軽い準備作業をする。APIが重いブロックを提供する場合は、スケルトンUIをレンダリングして、ユーザーがフィードバックを得られるようにする。こうすることでインタラクションを高速に保ち、その間にバックグラウンドでデータを処理する。 ロールイン.

// 例:非同期にロードする
document.addEventListener('DOMContentLoaded', async () => {)
  const res = await fetch('/wp-json/wp/v2/posts?_fields=id,title,slug&per_page=5', { cache: 'force-cache' });
  const posts = await res.json();
  // レンダー関数を呼び出す...
});

プロのための高度なテクニック

サービスワーカーは GET リクエストを受け取り、レスポンスを キャッシュ オフラインのときは直接配信する。定期的で高価なデータについては、トランジェントを保持するか、PHPが最小限の作業で済むようにRedisを使っている。Ajaxのノイズが回線を詰まらせないように、フロントエンドのハートビートを長い間隔に設定する。テーマのバラストを取り除く:未使用のCSS/JSは時間のコストになり、クリティカルパスを増加させる。cronジョブの場合、重いタスクは時間の少ない時間帯に延期する。 トラフィック.

測定:症状から原因へ

私はTTFB測定から始めて、キャッシュのヒットとミスを比較し、本当のことを理解する。 原因 クエリモニタは、どのクエリが優勢で、どのクエリにインデックスやサマリが必要かを示してくれる。クエリモニタは、どのクエリが優勢で、インデックスや要約が必要なのかを示してくれる。PageSpeedとWebバイタルデータは、LCP、INP、CLSの優先順位を明確にする。最初のバイトが遅い場合は、ホスティング、PHPバージョン、オブジェクトキャッシュ、ネットワークレイテンシをチェックする。より少ない呼び出しが必要な場合は、このガイドが役に立つ。 HTTPリクエストを減らす にて。 戦略.

カスタムエンドポイントのスキーマ設計と検証

カスタマイズされたエンドポイントは、次のような場合に特に優れたパフォーマンスを発揮する。 スキーム は最初から無駄がなく、厳格です。サーバーが無効なリクエストに対応する作業を減らし、クライアントが本当に必要なデータだけをリクエストできるように、タイプ、デフォルト、バリデーションでパラメーターを定義します。また、的を絞った方法でレスポンスを準備し、UI側で不要なフィールドを削除します。.

add_action('rest_api_init', function () {)
  register_rest_route('perf/v1', '/articles', [ )
    'methods' => 'GET'、
    'args' => [
      'per_page' => ['type' => 'integer', 'default' => 10, 'minimum' => 1, 'maximum' => 50]、
      '_fields' => ['type' => 'string'], // コアによって解析されます。
    ],
    'permission_callback' => '__return_true'、
    'callback' => function (WP_REST_Request $req) { 次のようにします。
      $q = new WP_Query([
        'post_type' => 'post'、
        'posts_per_page' => (int) $req->get_param('per_page')、
        'no_found_rows' => true, // 高価なCOUNT(*)を節約できます。
        'update_post_meta_cache' => true, // メタを一度に更新する
        'update_post_term_cache' => false, // タームデータを読み込まない
        'fields' => 'ids', // 最初にID、次にスリムフォーマット
      ]);
      $items = array_map(関数 ($id) {)
        return [
          'id' => $id、
          'title' => get_the_title($id)、
          'slug' => get_post_field('post_name', $id)、
        ];
      }, $q->posts);

      return new WP_REST_Response($items, 200);
    }
  ]);
});

と一緒に fields => ‚ids‘ データベースのオーバーヘッドを節約し、最小限のペイロードを自分で準備し、出力を自分のフロントエンドに正確に合わせることができる。有効化されたパラメータは、極端に大きなper_page値がAPIを遅くすることも防いでくれる。.

ページネーション、合計、COUNT() のコストを削減する

標準のコントローラはX-WP-TotalとX-WP-TotalPagesを提供する。これは便利なように聞こえるが、バックグラウンドでカウントされるため、しばしば多くの時間がかかる。UIでこのメタデータが必要ない場合は、クエリレベルの no_found_rows. .これにより、リスト・ビューにおけるデータベースの負荷が大幅に軽減される。.

// Totals für Post-Collection sparen
add_filter('rest_post_query', function ($args, $request) {
  if ($request->get_route() === '/wp/v2/posts') {
    $args['no_found_rows'] = true; // keine Totals, keine COUNT(*)
  }
  return $args;
}, 10, 2);

また、オフセットが大きい(page high、per_page large)場合は、顕著に遅くなることがある。そのような場合、私は カーソルベース 深いページを高いパフォーマンスでスクロールするために、別々のエンドポイントでのページネーション(例:IDや日付による)。.

キャッシュの検証と一貫性

キャッシュは、その 無効化. .私は明確なルールを定義している:投稿が保存されたり、そのステータスが変更された場合、私は影響を受けるキャッシュキーを削除または更新します。これにより、やみくもにすべてのキャッシュを空にすることなく、レスポンスを最新の状態に保つことができる。.

// Beispiel: gezielte Invalidierung bei Post-Änderungen
add_action('save_post', function ($post_id, $post, $update) {
  if (wp_is_post_revision($post_id)) return;

  // Keys nach Muster invalidieren (Object Cache / Transients)
  wp_cache_delete('perf:posts:list');        // Listenansicht
  wp_cache_delete("perf:post:$post_id");     // Detailansicht
}, 10, 3);

// 304 Not Modified korrekt bedienen
add_filter('rest_pre_serve_request', function ($served, $result, $request, $server) {
  $etag = $result->get_headers()['ETag'] ?? null;
  if ($etag && isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) === $etag) {
    // Schnellweg: keine Body-Ausgabe
    header('HTTP/1.1 304 Not Modified');
    return true;
  }
  return $served;
}, 10, 4);

重要 ゲット は公開キャッシュ可能でなければなりません。POST/PUT/PATCH/DELETEについては、積極的にno-cacheヘッダーを設定し、エッジ/ブラウザのキャッシュがそのようなレスポンスを保持しないようにする。.

セキュリティ:認証、クッキー、キャッシュ

認証された応答はしばしば パーソナル データ - これらは公にキャッシュされてはならない。私は、公開と非公開のレスポンスを厳密に区別し、Varyヘッダを適切に設定し、エッジキャッシュが有効になるように、GETでは不必要なクッキーを避けるようにしています。.

add_filter('rest_post_dispatch', function ($response, $server, $request) {
  if ($request->get_method() !== 'GET') return $response;

  if (is_user_logged_in()) {
    // Personalisierte Antwort: kein Public Caching
    $response->header('Cache-Control', 'private, no-store');
    $response->header('Vary', 'Authorization, Cookie, Accept-Encoding');
  } else {
    $response->header('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
    $response->header('Vary', 'Accept-Encoding');
  }
  return $response;
}, 10, 3);

管理エリアでのnonceセキュアなAjax呼び出しでは、キャッシュはタブーとされることが多い。一方、フロントエンドでは、エッジキャッシュを失格にしないように、クッキーは無駄のないものにしています(不必要なSet-Cookieヘッダーはありません)。これにより、パフォーマンスを犠牲にすることなくセキュリティを確保することができます。.

データモデル、インデックス、ストレージ戦略

メタ・クエリが優勢な場合は、次のようにチェックする。 データモデル. .常に一緒に使われるメタ・フィールドを正規化された構造や別のカスタム・テーブルに配置することは、しばしば役に立つ。既存のインストールでは、一般的な検索パターンを高速化するためにインデックスを使用することを考えています。.

-- 注意: 最初にステージングテストを行ってください!
CREATE INDEX idx_postmeta_key ON wp_postmeta (meta_key(191));
CREATE INDEX idx_postmeta_key_value ON wp_postmeta (meta_key(191), meta_value(191));;

これにより、典型的なWHERE meta_key = ‚x‘ AND meta_value LIKE ‚y%‘が大幅に短縮されます。また、WP_Queryに特定のフラグを設定しました: update_post_meta_cache を活性化させる、, update_post_term_cache 必要な場合のみ fields => ‚ids‘ 大規模なリストの場合。また トランジェント めったに変更されない集計のために、DBを顕著に緩和することができる。.

モニタリングと負荷テスト

なし モニタリング は盲目的な最適化である。レスポンス・タイム、ステータス・コード、キャッシュ・ヒット・レート、クエリ時間を記録している。負荷テストには、シンプルで再現可能なシナリオを使用します:1)コールドスタートとキャッシュの動作のためにバーストフェーズ(例:60秒間で50RPS)、2)安定性のために連続負荷(例:10分間で10RPS)。CPU、RAM、I/O待ち、DBロックをモニターすることは非常に重要である。PHP、データベース、ネットワークのいずれが制限されているかを認識する方法である。.

エラーパターンも重要です。429/503はレート制限または容量制限を示し、5xxはアプリケーションエラーを示します。私はタイムアウトを短く保ち、明確なエラーメッセージを提供し、リトライ(クライアント)が指数関数的バックオフを使用するようにします。これにより API 負荷のピークが発生した場合でも、堅牢である。.

典型的なアンチパターンとそれを避ける方法

  • 大型、ノーカット ペイロード をロードする:私は一貫して_fieldsを使用し、prepareコールバックで未使用のフィールドを削除しています。.
  • 関連データへの複数のリクエスト:構築する アグリゲーション・エンドポイント, まさにあなたが必要とする組み合わせを提供する。.
  • COUNT(*)と深いページネーション:私は次のように設定した。 no_found_rows 必要であれば、カーソルのページネーションに切り替える。.
  • 非均一なキャッシュヘッダ:私はパブリックとプライベートを厳密に区別し、次のように規制している。 TTL 話題性による。.
  • GET用クッキー:エッジキャッシュを有効にするため、クッキーは避けている。必要であれば、Varyを正しく設定する。.
  • 複雑な計算をその場で行う:事前に計算(トランジェント/レディス)を行い、変更があった場合は正確に無効にする。.
  • 非決定論的な出力:安定した イータグ 私は決定論的なソートとフィールドの順序を保証する。.

7日間のステップ・バイ・ステップ・プラン

1日目:TTFB、レスポンスサイズ、API呼び出し回数を測定し、次のことを明確にします。 ベースライン-値。2日目:_fieldsでフィールドを制限し、フロントエンドが実際にレンダリングするデータを正確に受け取るまで、per_pageを減らす。3日目:使用していないエンドポイントを削除し、_embedを無効化し、必要であれば無駄のないカスタムエンドポイントを構築する。4日目:N+1クエリを削除し、wp_optionsを整理し、WooCommerceが関係している場合はHPOSを有効にする。5日目: ETag、Cache-Control、Brotliを実装し、リクエストの頻度を減らして高速化する。 走り抜ける.

6日目:HTTP/3を保証し、Varyヘッダーを正しく設定し、keep-alive設定を調整する。7日目:最初のペイントの後に呼び出しを移動し、フェッチ経由で非同期にロードし、プリロードを特別に使用する。その後、同一のテストウィンドウで新たな測定を行い、効果を検証した。レポートでは、30~70 %小さいJSONと、著しく低いTTFB値がしばしば示されるようになりました。明確なロードマップがあるため、私は パフォーマンス 長期的には安定している。.

具体的なメリット

私は3つのステップで最大の効果を得る。 ペイロード, より少ないクエリー、より多くのキャッシュヒット。続いて、HTTP/3やBrotliなどのトランスポートの最適化、そして巧みなフロントエンドのローディング処理が行われます。これらの対策を組み合わせることで、コアとなるウェブのバイタルが明らかに改善され、コンバージョンがより安定し、スクロール時の動作が明らかに速くなります。毎日たくさんのAPIコールを処理している人なら、その効果を特に強く感じるだろう。私はこの順序にこだわり、すべての変更を文書化し、そして 結果 テストを繰り返しながら。.

現在の記事