HTTP 103 Early Hintsをlocalhostで観察する ― Node.jsとcurlで200との違いを確認

ネットワーク・RFCカテゴリを表すパンダのイラスト ネットワーク・RFC

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。RFC 8297とNode.jsのwriteEarlyHintsの仕様を確認し、localhostで情報応答と最終応答を見分ける実験を組み立てました。対象環境では実行していません。

検証ステータス:📘 RFC・Node.js公式資料確認済み/実機未確認

HTTPのステータスは200や404だけではありません。103 Early Hintsは、サーバーがHTMLなどの最終応答を返す前に、ブラウザーへリソースの読み込み候補を伝える情報応答です。103を見たことだけでは、サイトが正常終了したかどうかは分かりません。

この違いをlocalhostで観察します。Node.js 18.11以上とcurlがあれば、外部のサイトを使わずに試せます。

HTTP 103と200の役割

クライアント         サーバー
GET /       -------->
           <-------- 103 Early Hints
                     Link: </style.css>; rel=preload
           <-------- 200 OK
                     最終HTML

RFC 8297では103をinformational responseとして定義しています。読み込みの「ヒント」はクライアントによる先行準備の材料です。最終的な200や500の意味を置き換えるものではありません。

ステータス主な役割成功判定に使うか
103 Early HintsLinkなどの事前の手掛かり単独では使わない
200 OK通常の最終レスポンス応答内容と合わせて判断
404 Not Found対象が見つからない最終結果として確認
500 Internal Server Errorサーバー側の異常エラーとして扱う

動かしてみる

early-hints-local.jsというファイルを作ります。

const http = require("node:http");

const server = http.createServer((req, res) => {
  if (req.url === "/style.css") {
    res.writeHead(200, { "content-type": "text/css" });
    res.end("body { color: navy; }");
    return;
  }
  if (req.url !== "/") {
    res.writeHead(404);
    res.end("not found");
    return;
  }

  // 最終応答の準備が終わる前にLinkヒントを送る
  res.writeEarlyHints({
    link: "</style.css>; rel=preload; as=style"
  });
  setTimeout(() => {
    res.writeHead(200, {
      "content-type": "text/html; charset=utf-8",
      link: "</style.css>; rel=preload; as=style"
    });
    res.end("<!doctype html><h1>hello</h1>");
  }, 700);
});

server.listen(30031, "127.0.0.1", () => {
  console.log("http://127.0.0.1:30031/");
});

127.0.0.1でのみ待ち受けるため、外部には公開しません。ポート30031がほかのプロセスと衝突した場合は数字を変更してください。

端末Aでサーバーを起動し、端末Bでcurlを使います。

node early-hints-local.js
curl --http1.1 --include --no-progress-meter \
  http://127.0.0.1:30031/

期待されるレスポンスの並びです(実機出力ではありません)。

HTTP/1.1 103 Early Hints
Link: </style.css>; rel=preload; as=style

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
<!doctype html><h1>hello</h1>

サーバーを終了するときはCtrl+Cを押します。Node.jsの起動時にEADDRINUSEが出たら同じポートを別のプログラムが使っています。既存のサービスを停止するのではなく、サンプル側のポートを変えてください。

Daily-Code-Samples:HTTP 103のローカル実験に実行版と説明を置きました。

1か所変えて観察する

res.writeEarlyHints(...)の行をコメントアウトし、再起動して同じcurlを実行します。今度は103がなくなり、最終の200だけが残る想定です。

// res.writeEarlyHints({
//   link: "</style.css>; rel=preload; as=style"
// });

これで103と200が独立していることを確認します。さらにlocalhostでres.writeHead(500)へ変えれば、103が先に返っていても後でエラーになるケースを再現できます。

Linkヘッダーの意味と限界

</style.css>; rel=preload; as=styleの各部分は、事前読み込み候補のURL、関係(preload)、スタイルシートとしての扱いを示します。しかし、ブラウザーが必ず先読みするとは限りません。curlにヘッダーが出たことも、CSSがダウンロードされた証拠ではありません。

実際にリソースが早く取得されるかは、ブラウザーの開発者ツールのNetwork表示やパフォーマンス測定で検証します。キャッシュが効いている場合も、前提が変わります。

仕事で使う際の注意

プロキシ/CDNや古いHTTP/1.1クライアントは、情報応答を期待どおり扱わないことがあります。RFC 8297には情報応答の相互運用性についてのセキュリティ上の注意点があります。

また、HTTPの監視処理で、最初に見えた103を「応答終了」と扱わないことが重要です。103を受信した、最終ステータスが200だった、先読みが本当に行われたの3つを別々に記録します。

実サイトで使うなら、正しいLink先、実際の最終応答、クライアント互換性、負荷への影響を順番に確認します。導入の前後で実測しない限り、速度改善を断定しないでください。

公式資料

文書情報

記事タイトル
HTTP 103 Early Hintsをlocalhostで観察する ― Node.jsとcurlで200との違いを確認
作成日
更新日
Source URL
https://papanda925.com/?p=18081

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました