1. はじめに:Webリクエストの旅
日々、何十億ものユーザーがWebサイトにアクセスしていますが、そのシームレスな体験が当たり前のように感じられることがよくあります。しかし、その背後では、ユーザーのブラウザ、ネットワーク、そして複数のサーバー間で洗練された一連のイベントが繰り広げられています。単純なクリックやURL入力が、完全にインタラクティブなWebページへと変換されるこの複雑なプロセスは、まさに魔法のようです。本レポートでは、このWebリクエストの旅を段階的に解き明かし、その裏側で何が起こっているのかを詳細に解説します 1。
本レポートでは、まずWebを構成する主要な要素(ブラウザ、各種サーバー)とその役割を定義します。次に、通信の基盤となるプロトコル(DNS、TCP/IP、HTTP)を解説し、リクエストがどのようにサーバーに到達し処理されるか(サーバーサイド処理)を掘り下げます。さらに、ブラウザが受け取った情報をどのように解釈し、視覚的なページを構築するか(レンダリングパイプライン)、そしてJavaScriptがどのようにインタラクティブ性を付与するかを探求します。最後に、この一連の流れを視覚的にまとめた図の構成要素について説明します。
2. エコシステム:主要コンポーネントとその役割
Webサイトが表示されるまでには、様々な要素が連携して動作します。ここでは、その主要な登場人物とその役割について解説します。
2.1. クライアントサイドの主役:Webブラウザ
ユーザーがWebと対話するための主要なインターフェースがWebブラウザです。これは、Webリソース(HTML、CSS、JavaScript、画像など)を要求し、受信し、解釈し、そして表示する役割を担うソフトウェアです 2。クライアントサーバーモデルにおける「クライアント」として機能します 2。
注意すべき点として、Webブラウザと検索エンジンはしばしば混同されますが、その役割は異なります。ブラウザ(例:Google Chrome、Mozilla Firefox)は、特定のURLにあるWebページを表示するソフトウェアです。一方、検索エンジン(例:Google、Bing)は、他のWebサイトを探す手助けをするWebサイトです 3。ブラウザを起動した際に検索エンジンのホームページが表示されることが多いため、この混同が生じやすいです 3。
2.2. ネットワークインフラ:接続の組織
- DNS (Domain Name System): インターネットの「電話帳」に例えられます。人間が読みやすいドメイン名(例:www.example.com)を、サーバーを見つけるために必要な機械可読のIPアドレス(例:192.0.2.1)に変換します 2。ブラウザがサーバーと通信を開始する前に、まずDNSルックアップが行われます 5。
- TCP/IP (Transmission Control Protocol/Internet Protocol): インターネット上でデータがどのように移動するかを定義する基本的な通信プロトコル群です 2。クライアントとサーバー間で信頼性のあるデータ転送を保証します。データは、パケットと呼ばれる小さな塊に分割されて送信されます 2。これは、一部のパケットが失われたり破損したりした場合に再送を容易にし、また複数のユーザーが同時にWebサイトをダウンロードできるようにするためです 2。
- CDN (Content Delivery Network) (任意だが関連): 地理的に分散されたサーバーネットワークで、静的コンテンツ(画像、CSS、JSファイルなど)をユーザーの近くにキャッシュします。これにより、コンテンツ配信の遅延(レイテンシ)を削減し、オリジンサーバーの負荷を軽減します。基本的なWebサイト機能には必須ではありませんが、現代のWebパフォーマンスにおいて重要な役割を果たしています 7。
2.3. サーバーサイドのアンサンブル:コンテンツを動かす力
- Webサーバー (例: Nginx, Apache): 主にクライアント(ブラウザ)からのHTTP(S)リクエストを受け取る最初の窓口です 5。主な役割は、HTMLファイル、CSSファイル、画像ファイルなど、ファイルシステムから直接提供できる静的コンテンツを配信することです 8。また、リバースプロキシやロードバランサーとして機能し、動的コンテンツのリクエストを後述のアプリケーションサーバーに転送する役割も担います 8。Apache HTTP ServerやNginxが広く使われている代表例です 12。
- アプリケーションサーバー (APサーバー) (例: Node.jsランタイム, Python w/ Flask/Django, Ruby on Rails, Java w/ Tomcat): アプリケーションのビジネスロジックを実行するサーバーです 8。Webサーバーから転送された動的なリクエストを処理し、サーバーサイド言語(JavaScript (Node.js) 14、Python 15、PHP、Ruby、Java 10 など)で書かれたコードを実行します。必要に応じてデータベースと連携し、動的なコンテンツ(多くの場合HTML)を生成して、Webサーバー経由でクライアントに返します 8。内部通信にはHTTP以外のプロトコル(RMI、RPCなど)を使用することもあります 8。
- データベースサーバー (例: PostgreSQL, MySQL, MongoDB): アプリケーションのデータ(ユーザー情報、商品カタログ、投稿など)を格納、管理、取得するサーバーです 8。アプリケーションサーバーは、リクエストを処理するために必要なデータを取得したり変更したりするために、データベースサーバーにクエリを送信します 10。
多くの現代的なWebアプリケーションは、関心の分離を促進するために、明確な**3層構造(Three-Tier Architecture)**を採用しています。この構造は、ユーザーインターフェースを担当するプレゼンテーション層(Webサーバー)、ビジネスロジックを実行するアプリケーション層(アプリケーションサーバー)、そしてデータの永続化を管理するデータ層(データベースサーバー)から構成されます 13。この分離により、各層は独立して開発、スケーリング(例えば、Webサーバーの数を増やすなど)、保守が可能となり、システム全体の堅牢性と柔軟性が向上します 19。Webサーバー、アプリケーションサーバー、データベースサーバーの役割は、この3層構造に直接対応しています。
Webサーバーとアプリケーションサーバーの区別は、両方の機能を持つハイブリッドなサーバーソフトウェアも存在するため、時には曖昧になることもあります 8。しかし、この区別は、生のHTTPトラフィックや静的ファイルの処理と、複雑なアプリケーションロジックの実行という、根本的な役割分担を反映しています。静的なコンテンツのみを提供するシンプルなWebサイトであれば、Webサーバーだけで十分な場合があります 8。しかし、ユーザーの入力やデータベースの情報に基づいて動的にコンテンツを生成する必要があるインタラクティブなアプリケーションでは、アプリケーションサーバーが不可欠です 8。アプリケーションサーバーは、データベースアクセスを含む複雑なビジネスロジックを実行するように設計されています 8。一方、Webサーバーは、多数の同時HTTP接続を効率的に処理し、静的アセットを迅速に配信することに最適化されています 12。これらの役割を分離することで、各サーバータイプはそれぞれの専門タスクを最適に実行でき、結果としてパフォーマンス、スケーラビリティ(Web層とApp層を独立してスケール可能)、およびセキュリティ(Webサーバーが防御的なフロントエンドとして機能)が向上します。
3. 接続の開始:ユーザーアクションからサーバー発見まで
3.1. 発端:ユーザーアクション
すべてのプロセスは、ユーザーがブラウザのアドレスバーにURLを入力するか、Webページ上のハイパーリンクをクリックすることから始まります 2。URL(Uniform Resource Locator)には、プロトコル(例: http、https)、ドメイン名、そして場合によってはパスやクエリパラメータが含まれており、アクセスしたいリソースの場所を一意に示します 2。
3.2. ステップ1:DNSルックアップ – サーバーのアドレスを探す
ブラウザはまず、リクエストを送信する先のサーバーのIPアドレスを知る必要があります。URLからドメイン名を抽出し、DNSシステムに問い合わせます 2。
このプロセスでは、まずローカルキャッシュ(ブラウザ自身のキャッシュ、OSのキャッシュ)を確認します。キャッシュにIPアドレスが見つからない場合、再帰的DNSリゾルバーに問い合わせ、そこからルートサーバー、トップレベルドメイン(TLD)サーバー、そして最終的にそのドメインの権威DNSサーバーへと問い合わせが連鎖し、目的のIPアドレスを取得します 2。
DNSルックアップは、Webサイトの読み込み時間における最初の潜在的なボトルネックとなり得ます。DNSの解決が遅いと、ユーザーが感じるページの表示速度に直接影響します。なぜなら、ブラウザはサーバーのIPアドレスを知るまで、実際のコンテンツリクエストを開始できないからです 2。DNSルックアップはネットワークリクエストを伴い、場合によっては複数のサーバーを経由するため 20、各ホップで遅延が発生します。ローカルにIPアドレスがキャッシュされていない場合、この完全なルックアッププロセスが必要となり、HTTPリクエストを開始する前にかなりの遅延が生じる可能性があります。したがって、効率的なDNSインフラストラクチャと各レベルでのキャッシュ(ブラウザ、OS、ISPのリゾルバーなど)は、高速なWeb体験を実現するための最初の重要なステップです。
3.3. ステップ2:接続の確立 – TCPハンドシェイクとTLSネゴシエーション
IPアドレスが判明すると、ブラウザはサーバーとの間にTCP接続を確立しようとします。これは、3ウェイハンドシェイクと呼ばれるプロセスを通じて行われます。クライアントがSYN(同期)パケットを送信し、サーバーがSYN-ACK(同期応答確認)パケットを返し、最後にクライアントがACK(確認)パケットを送信することで、双方がデータ転送の準備ができたことを確認します 4。
URLがhttpsで始まる場合、TCPハンドシェイクが完了した後に、TLS (Transport Layer Security) ハンドシェイクが行われます 20。これは、クライアントとサーバー間で安全な(暗号化された)通信チャネルを確立するためのプロセスです。このハンドシェイクでは、使用する暗号化アルゴリズムの合意、サーバー証明書の交換と検証(サーバーの身元確認)、そして暗号化キーの生成と交換が行われます。このプロセスは、平文のHTTP接続と比較して、追加のネットワーク往復(ラウンドトリップ)を必要とします 20。
接続の確立、特に安全なHTTPS接続の確立には、複数のネットワークラウンドトリップが必要です。TCPは信頼性のある順序付けられたデータ配信を保証するために、最初のハンドシェイク(SYN -> SYN/ACK -> ACK)を必要とし、これには1回のラウンドトリップがかかります 6。HTTPSはセキュリティ(暗号化、認証)のためにTLSを必要とし 20、TLSハンドシェイクには証明書の交換や鍵のネゴシエーションなど、TCPハンドシェイクの後に追加のラウンドトリップ(通常、設定に応じて1〜2回)が必要です 20。各ラウンドトリップはネットワークの遅延によって制約されるため、接続確立フェーズ、特にHTTPSの場合は、ブラウザが実際にページコンテンツのHTTPリクエストを送信する前に固有の遅延が発生します。この遅延は、特に高レイテンシのネットワーク環境では無視できません。TLSセッション再開のような最適化技術は、後続の接続でこのセットアップ時間を短縮するために存在します。
4. リクエスト:ブラウザがページを要求する
4.1. ステップ3:HTTP(S)リクエストの作成
接続が確立されると、ブラウザはサーバーに対してHTTP(S)リクエストメッセージを送信します 2。
このリクエストメッセージは特定の構造を持っています:
- リクエストライン: HTTPメソッド(例: GET, POST)、リクエストURI(リソースへのパス、例: /index.html)、およびHTTPバージョン(例: HTTP/1.1, HTTP/2)を含みます 22。
- ヘッダー: リクエストやクライアントに関する追加情報を提供するキーと値のペアです(例: Host(必須)、User-Agent、Accept、Accept-Language、Cookieなど)22。
- ボディ (任意): サーバーに送信されるデータを含みます。通常、POSTやPUTのようなメソッドで使用されます(例: フォームの送信データ、JSONペイロード)22。
HTTPメソッドは、クライアントがサーバーに対して実行したいアクションを定義します 3。これらのメソッドを理解することは、ブラウザがサーバーとどのように対話し、Web APIがどのように設計されるかを理解する上で不可欠です。以下は、よく使用されるHTTPリクエストメソッドの概要です。
メソッド | 目的 | ボディの使用 | 冪等性 | 安全性 |
GET | 指定されたリソースを取得する | 通常なし | Yes | Yes |
POST | データをサーバーに送信する(リソース作成など) | 通常あり | No | No |
PUT | 指定されたリソースを更新または作成する | 通常あり | Yes | No |
DELETE | 指定されたリソースを削除する | 通常なし | Yes | No |
HEAD | GETと同様だが、レスポンスボディなしでヘッダーのみ取得 | なし | Yes | Yes |
OPTIONS | ターゲットリソースの通信オプションを記述する | 通常なし | Yes | Yes |
PATCH | リソースに部分的な変更を適用する | 通常あり | No | No |
(出典: 3)
冪等性(Idempotent): 同じリクエストを複数回実行しても、結果が常に同じである(サーバーの状態が同じになる)性質。
安全性(Safe): リクエストによってサーバーの状態が変更されることを意図しない性質。GETやHEADは安全とみなされます。
5. サーバーサイドの物語:リクエストの処理
5.1. ステップ4:Webサーバーによる受信とルーティング
通常、サーバーサイドでの最初の接点はWebサーバー(例: Nginx, Apache)です。WebサーバーはクライアントからのHTTPリクエストを受信します 8。
Webサーバーはリクエスト(メソッド、URI、ヘッダー)を解析します。もしリクエストが自身で直接提供できる静的ファイル(例: /images/logo.png)に対するものであれば、ファイルを読み込み、レスポンスを準備します 8。
もしリクエストが動的な処理を必要とする場合(例: /login、/api/products)、Webサーバーはリバースプロキシとして機能し、設定されたルールに基づいてリクエストを適切なアプリケーションサーバーに転送します 8。
5.2. ステップ5:アプリケーションサーバーによるビジネスロジックの実行
アプリケーションサーバーは、Webサーバーから転送されたリクエストを受け取ります。ここで、アプリケーションの中核となるコードが実行されます 8。
Express (Node.js) 27、Flask/Django (Python) 29、Ruby on Rails、Spring (Java) といったWebフレームワークは、この処理を構造化し、ルーティング(URLと処理関数のマッピング)、リクエスト解析、ミドルウェア(リクエスト/レスポンス処理の間に挟まる関数)の実行などを容易にします 19。
アプリケーションロジックは、リクエストの詳細に基づいて実行されます(例: ログイン資格情報の検証、ユーザーデータの取得、ショッピングカートの合計計算など)。これには、Node.js 14、Python 15、PHP、Ruby、Java 10 などの言語で書かれたコードの実行が含まれます。
サーバーは多数のクライアントリクエストを同時に処理する必要があります 33。単純なシングルスレッドのブロッキングモデルでは、一度に1つのリクエストしか処理できず、パフォーマンスと応答性が低下します 33。この課題に対応するため、アプリケーションサーバーは効率的な並行処理メカニズムを採用しています。特にNode.jsは、シングルスレッドのイベントループとノンブロッキングI/Oモデルを使用します 32。I/O操作(データベースクエリなど)を開始すると、完了を待たずに(ブロックせずに)次のリクエストの処理に移り、I/O完了時にコールバック関数が実行されます。これはI/Oバウンドな(ディスクやネットワーク待ちが多い)タスクに効率的です。一方、PythonやJavaなどの他のプラットフォームでは、Gunicorn 33 やTomcat 10 といったサーバーによって管理される複数のスレッドやプロセス(ワーカー)を使用することが一般的です。各ワーカーがリクエストを処理することで並列処理を実現し、これはCPUバウンドな(計算処理が多い)タスクに適している場合があります 8。採用される並行処理モデルは、アプリケーションサーバーが負荷下でどのようにスケールし、パフォーマンスを発揮するかに影響を与えます。
5.3. ステップ6:データベースとの連携
リクエストがデータ(例: ユーザープロフィールの取得、商品リストの表示)を必要とする場合、アプリケーションサーバーはデータベースサーバーに接続します 8。
アプリケーションサーバーは、データの取得、挿入、更新、削除を行うために、クエリ(多くの場合SQL、またはORMを介して)をデータベースサーバーに送信します 15。
Object-Relational Mapper (ORM)、例えばSQLAlchemy (Python) 15 やPrisma (Node.js/TypeScript) 36 などが、データベース操作を抽象化するためによく使用されます。これにより、開発者は生のSQLクエリを書く代わりに、プログラミング言語のオブジェクトを操作する形でデータベースを扱えるようになります 15。異なるベンダーのデータベース(例: PostgreSQLとMySQL)を単一のアプリケーションから参照することも、ORMを使用すれば可能です 39。
データベースサーバーはクエリを処理し、結果をアプリケーションサーバーに返します 10。効率化のため、アプリケーションサーバーはデータベース接続を再利用するための接続プールを管理することが一般的です 10。
データベースとの対話は、しばしばパフォーマンスクリティカルなステップとなります。多くの動的なWebリクエストはデータベースへのアクセスや変更を必要とします 8。データベース操作には、アプリケーションサーバーとデータベースサーバー間のディスクI/Oやネットワーク通信が含まれ、これらはメモリ内操作と比較して時間がかかる可能性があります。非効率なクエリ(例: インデックスなしでの大規模テーブルのスキャン)は、応答時間を大幅に増加させる可能性があります。ORMは開発を簡素化しますが、注意深く使用しないと非効率なクエリを生成することもあります 38。したがって、データベーススキーマ、クエリ、および接続管理 10 の最適化は、バックエンドのパフォーマンスにとって極めて重要であり、ユーザーが感じる速度に直接影響します。
5.4. ステップ7:動的レスポンスの生成
アプリケーションサーバーは、実行したロジックの結果(およびデータベースから取得したデータ)を使用して、レスポンスのコンテンツを構築します 8。
これには以下のような作業が含まれる場合があります:
- テンプレートエンジンを使用してHTMLページをレンダリングする(プレースホルダーを動的データで埋める)。
- APIリクエストに対してJSONペイロードを生成する 25。
- 必要に応じて他のデータ形式を準備する。
生成されたコンテンツが、HTTPレスポンスのボディ部分を形成します。
6. レスポンス:サーバーがページの構成要素を送り返す
6.1. ステップ8:HTTP(S)レスポンスの構築と送信
アプリケーションサーバーは、生成したコンテンツをWebサーバー(プロキシとして使用されている場合)に返します。Webサーバー(または直接アプリケーションサーバー)が最終的なHTTP(S)レスポンスメッセージを構築します 8。
レスポンスメッセージはリクエストの構造を反映していますが、結果を提供します:
- ステータスライン: HTTPバージョン、ステータスコード(例: 200)、および理由フレーズ(例: OK)を含みます 22。
- ヘッダー: レスポンスやサーバーに関する情報を提供するキーと値のペアです(例: Content-Type、Content-Length、Set-Cookie、Cache-Control、Server、Date、Last-Modified)20。Content-Typeヘッダーは特に重要で、ブラウザにボディの解釈方法(例: text/html、application/json、image/jpeg)を伝えます 22。
- ボディ: 実際に要求された、または生成されたリソース(HTMLドキュメント、JSONデータ、画像ファイルなど)を含みます 2。
レスポンスは、確立されたTCP/IP接続を介して(HTTPSを使用している場合はTLSで暗号化されて)ブラウザに送り返されます。データはパケットで送信されます 2。
HTTPステータスコードは、サーバーがリクエストの処理結果をクライアントに伝えるための主要な手段です 22。異なるコードは、成功、リダイレクト、クライアントエラー、サーバーエラーなど、さまざまな状況を示します 23。これらのコードを理解することは、Webアプリケーションのデバッグ(例: 404 Not Foundと500 Internal Server Errorの区別)や、レスポンスのプログラム的な処理(例: 3xxコードに対するリダイレクトの追跡)に不可欠です。以下は、一般的なHTTPステータスコードの分類と例です。
コード範囲 | クラス | 代表的なコード | 理由フレーズ | 意味 |
1xx | 情報 | 100 | Continue | リクエストの継続が可能であることを示す |
2xx | 成功 | 200 | OK | リクエストが成功した |
201 | Created | リクエストが成功し、リソースが作成された | ||
204 | No Content | リクエストは成功したが、返すコンテンツがない | ||
3xx | リダイレクション | 301 | Moved Permanently | リソースが恒久的に移動した |
302 | Found (Moved Temporarily) | リソースが一時的に移動した | ||
304 | Not Modified | リソースは変更されていない(キャッシュ利用可能) | ||
4xx | クライアントエラー | 400 | Bad Request | リクエストが無効 |
401 | Unauthorized | 認証が必要 | ||
403 | Forbidden | アクセスが禁止されている | ||
404 | Not Found | リクエストされたリソースが見つからない | ||
5xx | サーバーエラー | 500 | Internal Server Error | サーバー内部でエラーが発生した |
502 | Bad Gateway | ゲートウェイ/プロキシサーバーが不正なレスポンスを受け取った | ||
503 | Service Unavailable | サービスが一時的に利用不可(過負荷やメンテナンス) |
(出典: 2)
7. ブラウザレンダリング:視覚的なページの構築(クリティカルレンダリングパス)
ブラウザは、サーバーから送られてきたHTTPレスポンス、特に最初のHTMLドキュメントを受信します。このコードをユーザーが見ることのできるピクセルに変換するプロセスは、クリティカルレンダリングパス (Critical Rendering Path) と呼ばれます 20。このパスを最適化することが、高速なページ読み込みの鍵となります 20。
7.1. ステップ9:HTMLの解析 → DOM (Document Object Model) ツリー
ブラウザはHTMLドキュメントの生バイトデータを読み込み、指定されたエンコーディング(例: UTF-8)に基づいて文字に変換します。次に、これらの文字を意味のある塊(トークン、例: <html>, <head>, <body>, <p>)に分割します(Tokenizing)。これらのトークンはNodeオブジェクトに変換され(Lexing)、最終的にこれらのノードがツリー構造(DOM Tree)に組み立てられます 2。
DOMはドキュメントの論理的な構造を表現し、JavaScriptなどを介してドキュメントを操作するためのAPIを提供します 2。HTMLの解析は、エラー(例: 閉じタグの欠落)があっても処理を続行できるように、非常に寛容に設計されています 46。
HTMLの解析中、ブラウザはCSS、JavaScript、画像などの外部リソースへのリンク(例: <link>, <script>, <img> タグ)に遭遇します。多くの場合、「プリロードスキャナー」と呼ばれる機能が並行して動作し、これらのリソースを早期に発見してバックグラウンドでダウンロードを開始します。これにより、後続の処理を待たずにリソース取得を開始でき、全体の読み込み時間を短縮できます 20。
7.2. ステップ10:CSSの解析 → CSSOM (CSS Object Model) ツリー
ブラウザは、HTML解析中に遭遇したCSS(インラインの<style>タグや、<link>タグで参照される外部CSSファイル)を解析します。HTMLと同様に、バイト → 文字 → トークン → ノードというプロセスを経て、最終的にCSSOM (CSS Object Model) ツリーを構築します 2。
CSSOMは、DOM要素に適用されるスタイルルールをブラウザが理解できる形式で表現したものです。これには、CSSファイルで明示的に宣言されたスタイル、親要素から継承されたスタイル、ブラウザのデフォルトスタイルなどが含まれ、CSSカスケーディングルールに基づいて最終的なスタイルが決定されます 20。
CSSの解析は、レンダリングをブロックする可能性があります。画像読み込みなどは非同期で行われ、レンダリングを直接ブロックしませんが、ブラウザは要素を画面にどのように配置し描画するかを知るためにCSSOMが必要です。もしCSSOMが構築される前にコンテンツをレンダリングしてしまうと、スタイルが適用されていないコンテンツが一瞬表示された後にスタイルが適用される「Flash of Unstyled Content (FOUC)」が発生し、ユーザー体験を損ないます。これを避けるため、ブラウザは通常、DOMとCSSOMの両方が利用可能になるまでレンダリング(具体的には次のステップであるレンダーツリーの構築)を待ちます。したがって、CSSの読み込みと解析はレンダーブロッキングリソースと見なされ、遅いCSS配信や複雑なCSS解析は、ページの初期描画を遅らせる可能性があります。
7.3. ステップ11:レンダーツリーの作成
ブラウザは、構築されたDOMツリーとCSSOMツリーを組み合わせてレンダーツリー (Render Tree) を作成します 20。
レンダーツリーには、ページに実際に表示されるノードのみが含まれます。表示されないノード(例: <head>要素や、CSSでdisplay: none;が指定された要素)は省略されます。ただし、visibility: hidden;が指定された要素は、レイアウト空間を確保するためレンダーツリーに含まれます。レンダーツリーの各ノードは、そのコンテンツと、CSSOMから計算された最終的なスタイル情報を持っています 20。
7.4. ステップ12:レイアウト(ジオメトリと位置の計算 – リフロー)
レンダーツリーが構築されると、ブラウザはビューポート(表示領域)内で各ノードの正確なサイズと位置を計算します。この段階はレイアウト (Layout) またはリフロー (Reflow) と呼ばれます 20。
ブラウザは、各要素の計算済みスタイル(幅、高さ、マージン、パディングなど)と、それが含まれる要素やビューポートの寸法に基づいて、要素の幾何学的情報(ジオメトリ)を決定します 20。
レイアウト計算は、計算コストが高い処理です。ページ上の要素は互いの位置に影響を与えるため(例えば、ある要素の幅が変わると、後続の要素が下に押し出されたり、テキストが折り返されたりする 20)、ブラウザはこれらの相互依存関係を正確に計算する必要があります。要素のジオメトリが後から変更されると(例えば、JavaScriptによる幅の変更やウィンドウのリサイズ)、その要素だけでなく、影響を受ける可能性のある他の多くの要素、場合によってはドキュメント全体のレイアウトを再計算する必要が生じることがあります。これは「リフロー」と呼ばれ、特に頻繁に発生すると「レイアウトスラッシング」を引き起こし、パフォーマンスに大きな影響を与える可能性があります。
7.5. ステップ13:ペイント(ピクセルの描画 – ラスタライズ)と合成
レイアウトが完了すると、ブラウザは各ノードの視覚的なコンテンツ(テキスト、色、境界線、影、画像など)を画面上の実際のピクセルに変換します。このプロセスはペイント (Paint) またはラスタライズ (Rasterize) と呼ばれます 20。
パフォーマンスを向上させるため、特にスクロールやアニメーションを滑らかにするために、ブラウザはしばしばページコンテンツを複数の**レイヤー(合成レイヤー)**に分けてペイントします 20。独立して変化する可能性のある要素(例えば、CSSのtransformやopacityでアニメーションされる要素)は、独自のレイヤーに配置されることがあります。
最後のステップは合成 (Compositing) です。ここで、ペイントされた複数のレイヤーが正しい順序(z-indexなどを考慮)で画面上に重ね合わされ、最終的なページ画像が生成されます。この合成処理は、多くの場合、GPU (Graphics Processing Unit) によって効率的に処理され、メインスレッドの負荷を軽減できます 20。
特定のCSSプロパティ(例: transform: translateZ(0); や will-change)を使用して要素を独自のレイヤーに「昇格」させることは、再ペイントと合成を最適化する一般的な手法です。要素が自身のレイヤーにある場合、transformやopacityのような変更は、多くの場合、他のレイヤーのレイアウトやペイントを再実行することなく、GPUによるそのレイヤーの再合成のみで済みます 20。これにより、アニメーションやスクロールが大幅に高速化されます。しかし、各レイヤーはGPUメモリ内にテクスチャとして保持されるため 20、レイヤーを過剰に作成するとメモリ消費量が増加し、初期のレイヤー設定が遅くなる可能性があり、パフォーマンス上の利点が相殺されることもあります。これは慎重な検討を要するトレードオフです。
8. インタラクティビティ:JavaScriptの登場
8.1. ステップ14:JavaScriptの解析と実行
HTMLパーサーが<script>タグに遭遇すると(asyncまたはdefer属性が付いていない限り)、通常、HTMLの解析を一時停止し、JavaScriptコードをダウンロード(外部ファイルの場合)、解析、コンパイル、そして実行します 2。
JavaScriptコードの解析とコンパイルには、字句解析(コードをトークンに分割)、構文解析(トークンから抽象構文木 (Abstract Syntax Tree – AST) を構築)、そしてブラウザのJavaScriptエンジン(例: V8 (Chrome), SpiderMonkey (Firefox))による実行可能な形式(バイトコードや、JIT (Just-In-Time) コンパイルによる機械語)への変換が含まれます 20。
デフォルトでは、JavaScriptの実行はレンダーブロッキングかつパーサーブロッキングです。これはパフォーマンス上の大きな考慮事項です。なぜなら、JavaScriptはDOM構造(例: document.write()の使用)やCSSOM(スタイル変更)を潜在的に変更できるためです 2。もしHTMLパーサーがJavaScriptの実行中に解析を続けると、スクリプトが不完全または不正なDOM/CSSOMに対して動作してしまう可能性があります。一貫性を保つため、ブラウザはHTMLの解析を一時停止し、スクリプトの実行が完了するのを待ってから解析を再開します 46。レンダリングは通常、完成したDOMとCSSOMに依存するため、パーサーをブロックすることは事実上レンダリングもブロックします。これが、<head>内など、HTMLの早い段階に配置された大きなスクリプトや読み込み/実行に時間のかかるスクリプト(特にdeferやasyncなしの場合)が、ページのレンダリングとインタラクティブ性を著しく遅延させる可能性がある理由です。<script>タグにasync(実行順序を保証せず、準備ができ次第実行)またはdefer(HTML解析後に順序通り実行、DOMContentLoadedイベント前)属性を使用することが、パフォーマンス向上のために重要です 46。
8.2. ステップ15:DOMとCSSOMの操作
実行されたJavaScriptコードは、Web APIを使用してDOM(要素の追加/削除、コンテンツの変更 45)やCSSOM(スタイルの変更 48)と対話するのが一般的です。これらの操作により、初期レンダリング後にページの構造や外観を動的に変更できます。
DOMやCSSOMの操作は、後続のリフロー(レイアウト)やリペイントを引き起こす可能性があり、効率的に行わないとパフォーマンスに影響を与える可能性があります 20。React、Vue、Angularのようなフロントエンドフレームワークは、仮想DOMや最適化された更新戦略を用いて、これらの更新をより効率的に管理することがよくあります。
8.3. ステップ16:非同期操作の処理 (AJAX/Fetch API)
JavaScriptは、ページ全体の再読み込みなしに動的な更新を可能にする非同期リクエストを実現します。XMLHttpRequest(古い方法で、「AJAX」としばしば関連付けられる)や、より現代的なFetch APIといった技術により、スクリプトはバックグラウンドでサーバーからデータ(例: JSON、テキスト、HTMLフラグメント)を要求できます 2。
これらのリクエストは非同期です。スクリプトはリクエストを開始した後、他のコードの実行を続けます。サーバーが応答すると、コールバック関数またはPromiseハンドラーが実行され、受信したデータを処理します 32。
受信したデータは、DOMやCSSOMを更新するために使用され、ページの特定の部分を動的に変更します(例: 新しい投稿の読み込み、ショッピングカートの更新、検索結果の表示)50。
非同期JavaScriptリクエスト(Fetch/AJAX)は、現代的でインタラクティブなWebアプリケーション(特にシングルページアプリケーション – SPA)の基礎です。従来のページ全体を再読み込みするモデルと比較して、動的なコンテンツ読み込みと、よりスムーズでアプリのようなユーザー体験を可能にします。従来のWebナビゲーションでは、すべてのインタラクションで完全に新しいHTMLページを要求し、ページ全体の再読み込みが発生していました 50。これは、特にデータ駆動型のアプリケーションでは遅く、途切れ途切れに感じられることがあります。Fetch/AJAXを使用すると、ブラウザは更新に必要なデータのみをサーバーに要求でき、多くの場合JSONのような軽量な形式で済みます 50。リクエストはバックグラウンドで非同期に行われ、ユーザーインターフェースをブロックしません 52。JavaScriptはデータを受信し、既存のページの関連部分のみのDOMを更新します 50。これにより、体感パフォーマンスが向上し、データ転送量が削減され、より流動的でインタラクティブな体験が実現します。これがSPAや多くの動的Web機能の基盤となっています。
9. 全体の流れの視覚化:プロセス図(シーケンス図の説明)
これまでのステップ全体の理解を深めるために、エンドツーエンドの流れを示す視覚的な図が非常に役立ちます。特に、異なるコンポーネント(ライフライン)間の時間経過に伴う相互作用(メッセージ)を示すには、シーケンス図が適しています 53。あるいは、ステップと決定の順序を示す詳細なフローチャートも有効です 6。
以下に、このプロセスを表すシーケンス図の構成要素とメッセージの流れを記述します。
- ライフライン/アクター:
- ユーザー (User)
- ブラウザ (Browser)
- DNSサーバー (DNS Server)
- Webサーバー (Web Server)
- アプリケーションサーバー (Application Server)
- データベースサーバー (Database Server)
- メッセージ/ステップのシーケンス:
- User -> Browser: URL入力 / リンククリック
- Browser -> DNS Server: DNSクエリ (ドメイン名)
- DNS Server -> Browser: DNSレスポンス (IPアドレス)
- Browser -> Web Server: TCPハンドシェイク (SYN, SYN/ACK, ACK)
- Browser -> Web Server: TLSハンドシェイク (ClientHello, ServerHello, Certificate, Key Exchange, Finished) – **
- Browser -> Web Server: HTTP(S) GET/POSTリクエスト (メソッド, URI, ヘッダー, [ボディ])
- Web Server -> Application Server: [alt: 動的リクエストの場合] リクエスト転送
- Application Server -> Database Server: [opt: データが必要な場合] データベースクエリ (例: SQL via ORM)
- Database Server -> Application Server: [opt] クエリ結果
- Application Server -> Web Server: [alt: 動的リクエストの場合] 生成されたレスポンスコンテンツ (例: HTML, JSON)
- Web Server -> Browser: HTTP(S)レスポンス (ステータス, ヘッダー, ボディ)
- Browser: HTML解析 -> DOM構築
- Browser: CSS解析 -> CSSOM構築
- Browser: DOM + CSSOM -> レンダーツリー作成
- Browser: レイアウト (ジオメトリ計算)
- Browser: ペイント (ラスタライズ) & 合成
- Browser: JavaScript解析 & 実行 – [レンダー/パーサーブロッキング]
- Browser (JS) -> Browser (DOM/CSSOM): ページ操作 (DOM/CSSOM変更) – [リフロー/リペイントの可能性]
- Browser (JS) -> Web/App Server: [loop: 非同期更新が必要な場合] Fetch/AJAXリクエスト
- Web/App Server -> Browser (JS): [loop] Fetch/AJAXレスポンス
- Browser (JS) -> Browser (DOM/CSSOM): [loop] 非同期データでページ更新
このシーケンス図では、各コンポーネントが縦のライフラインで表され、時間の経過とともに上から下へメッセージ(矢印)が交換されます。アクティベーションバー(ライフライン上の長方形)は、各コンポーネントが処理を行っている期間を示します 53。alt(選択)やopt(任意)、loop(繰り返し)といった複合フラグメント 53 を使用して、条件分岐やオプションのステップ、非同期更新の繰り返しなどを表現できます。
10. まとめ:全体像
本レポートでは、ユーザーの単純なアクションから始まるWebリクエストの旅を追跡しました。DNSルックアップとネットワークハンドシェイクを経て、リクエストはサーバーに到達します。サーバーサイドでは、Webサーバー、アプリケーションサーバー、データベースサーバーが連携し、静的コンテンツの配信や動的コンテンツの生成を行います。生成されたレスポンスは、HTTP(S)プロトコルを通じてブラウザに返送されます。ブラウザは受け取ったHTML、CSS、JavaScriptを解釈し、DOM、CSSOM、レンダーツリーを構築し、レイアウト、ペイント、合成という複雑なレンダリングパイプラインを経て、最終的に視覚的でインタラクティブなWebページをユーザーに提示します 2。
このプロセス全体を通じて、フロントエンド(ブラウザでのレンダリング、ユーザーインタラクション、クライアントサイドJavaScript)とバックエンド(サーバーロジック、データ管理)の間で明確な関心の分離が行われていることがわかります。これらは異なる役割を担いますが、HTTP、TCP/IPといった標準化されたプロトコルと、HTML、CSS、JavaScript、JSONといった共通のデータ形式を通じてシームレスに連携することで、現代のWebは機能しています 2。Webサイトが表示されるという一見単純な事象は、実際にはこれらの技術スタックが協調して動作する複雑なオーケストレーションの結果なのです。
引用文献
- ウェブ標準 – ウェブ開発の学習 – MDN Web Docs – Mozilla, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Learn_web_development/Getting_started/Web_standards
- ウェブのしくみ – ウェブ開発の学習 | MDN, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works
- ウェブの閲覧 – ウェブ開発の学習 – MDN Web Docs, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web
- Webの仕組み – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/harukin721/items/ad42c132f0fc64202b80
- ウェブの仕組み – ウェブ開発の学習 – MDN Web Docs – Mozilla, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Learn_web_development/Howto/Web_mechanics
- 【図解HTTP・HTTPS】Web閲覧時の通信フローについて …, 4月 19, 2025にアクセス、 https://shanai-neet.com/?p=3759
- 基礎から深堀りするWebアプリケーションアーキテクチャ – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/mai_mizz/articles/350d1dea1c75be
- ウェブサーバーとアプリケーションサーバーの違い – テクノロジー …, 4月 19, 2025にアクセス、 https://aws.amazon.com/jp/compare/the-difference-between-web-server-and-application-server/
- webサーバとアプリケーションサーバの違い #nginx – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/sabawo/items/5fd4a6f95672b5694359
- アプリケーションサーバとは?Webサーバとの違いや4つのメリットを解説 – 比較ビズ, 4月 19, 2025にアクセス、 https://www.biz.ne.jp/matome/2004479/
- アプリケーションサーバってなに?Webサーバとの違い|CX PICKS, 4月 19, 2025にアクセス、 https://www.marketingbank.jp/blog/%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%90%E3%81%A3%E3%81%A6%E3%81%AA%E3%81%AB%EF%BC%9Fweb%E3%82%B5%E3%83%BC%E3%83%90%E3%81%A8%E3%81%AE/
- Webサーバーとアプリケーション・サーバー – IBM, 4月 19, 2025にアクセス、 https://www.ibm.com/jp-ja/think/topics/web-server-application-server
- Webアプリケーションサーバとは?3層構成の仕組みと導入のメリット – 発注ナビ, 4月 19, 2025にアクセス、 https://hnavi.co.jp/knowledge/blog/web-application-server/
- Node.js + Express でPOSTデータを取得後、WebAPIへ問い合わせる – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/TakeshiNickOsanai/items/b1720dcbe2bb5f9e524f
- FastAPI|DB接続してCRUDするPython製APIサーバーを構築 – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/mtitg/items/47770e9a562dd150631d
- Webアプリケーションとアプリケーションサーバーの比較 / PumaやRackの話も少し – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/yusuke2310/items/2035304f46d3fe068e7e
- Webサーバとアプリケーション サーバの比較 – F5, 4月 19, 2025にアクセス、 https://www.f5.com/ja_jp/glossary/application-server-vs-web-server
- Webアプリケーションサーバとは?Webサーバとの違いや3層構造についても解説, 4月 19, 2025にアクセス、 https://dx.nid.co.jp/column/what-is-a-web-application-server
- 【Web】Webアプリケーションの基本について図を使って説明して …, 4月 19, 2025にアクセス、 https://qiita.com/nomikazu_x/items/e86a556ddaff4d049445
- ページの生成: ブラウザーの動作の仕組み – ウェブパフォーマンス …, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Web/Performance/Guides/How_browsers_work
- ブラウザーがウェブサイトを読み込む仕組み – ウェブ開発の学習 – MDN Web Docs, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites
- HTTPリクエスト、HTTPレスポンスとは #HTTP – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/minateru/items/8693538bbd0768855266
- HTTPリクエストとは?基本構造と仕組みを徹底解説 – Innovative, 4月 19, 2025にアクセス、 https://innovative.jp/archives/496
- Flask HTTP methods, handle GET & POST requests – GeeksforGeeks, 4月 19, 2025にアクセス、 https://www.geeksforgeeks.org/flask-http-methods-handle-get-post-requests/
- Python Flask – Request Object | GeeksforGeeks, 4月 19, 2025にアクセス、 https://www.geeksforgeeks.org/python-flask-request-object/
- Lesson.5 リクエスト&レスポンス – ロジコヤ, 4月 19, 2025にアクセス、 https://logicoya.com/course/lesson/63
- Express.jsとは?Node.jsのバックエンドフレームワークの詳細解説 | 株式会社一創, 4月 19, 2025にアクセス、 https://www.issoh.co.jp/tech/details/3857/
- Node.jsのExpressとは?特徴や使い方、APIを作成する方法について解説 | NEUTRAL, 4月 19, 2025にアクセス、 http://saas.n-works.link/programming/javascript/node_js_express_how_to_use
- The Request Context — Flask Documentation (3.1.x), 4月 19, 2025にアクセス、 https://flask.palletsprojects.com/en/stable/reqcontext/
- How Are Requests Processed in Flask? | TestDriven.io, 4月 19, 2025にアクセス、 https://testdriven.io/blog/how-are-requests-processed-in-flask/
- Fastify徹底解説:高性能なNode.jsウェブフレームワーク – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/Leapcell/items/7e9fb16175055853476f
- Node.jsを初めて学ぶ人が覚えるべきこと – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/daiyaone/articles/5da30a5b248351
- How does a single running instance of a Flask application handle multiple requests at once? Is it all async or multithreaded? Or handled by the webserver (NGINX, gunicorn, etc)? – Reddit, 4月 19, 2025にアクセス、 https://www.reddit.com/r/flask/comments/xv0js7/how_does_a_single_running_instance_of_a_flask/
- Node.js – サーバーサイドのJavaScript – azukiazusa.dev, 4月 19, 2025にアクセス、 https://azukiazusa.dev/blog/node-js/
- 【Prisma入門】次世代ORMで簡単にデータベース管理ができるようになろう – YouTube, 4月 19, 2025にアクセス、 https://www.youtube.com/watch?v=9mE1j1vzUAQ
- Prisma: Node.js & TypeScript向けの完璧なORM – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/kanasugi/articles/a082bd39c5bdf2
- Prismaの導入とメリットを考える #Node.js – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/am_765/items/5e42bd5f87b296f61fbc
- Drizzle ORM と TiDB Serverless の連携 (Node 20.x) – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/kameoncloud/articles/28c4854f471e81
- 1つのWEBアプリが複数ベンダーのDBを参照することの是非 – スタック・オーバーフロー, 4月 19, 2025にアクセス、 https://ja.stackoverflow.com/questions/94142/1%E3%81%A4%E3%81%AEweb%E3%82%A2%E3%83%97%E3%83%AA%E3%81%8C%E8%A4%87%E6%95%B0%E3%83%99%E3%83%B3%E3%83%80%E3%83%BC%E3%81%AEdb%E3%82%92%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AE%E6%98%AF%E9%9D%9E
- HTTPリクエスト/レスポンスの構成要素を初心者にも分かるように解説してみた – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/koheiyamaguchi0203/items/5777c4653a01ae4c7b06
- ブラウザでWebサイトが表示されるまでの仕組みを整理してみた #dns – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/fujifuji1414/items/f9c53b451fa4890b8bfc
- Handling Application Errors — Flask Documentation (3.1.x), 4月 19, 2025にアクセス、 https://flask.palletsprojects.com/en/stable/errorhandling/
- ブラウザレンダリングのプロセスを理解する #パフォーマンス – Qiita, 4月 19, 2025にアクセス、 https://qiita.com/fujisho1216/items/94a4f74379642f6f282f
- Webブラウザのレンダリングの仕組みを理解する – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/oreo2990/articles/280d39a45c203e
- ブラウザレンダリングの仕組み – Zenn, 4月 19, 2025にアクセス、 https://zenn.dev/ak/articles/c28fa3a9ba7edb
- Inside look at modern web browser (part 3) | Blog | Chrome for …, 4月 19, 2025にアクセス、 https://developer.chrome.com/blog/inside-browser-part3
- Populating the page: how browsers work – Web performance | MDN, 4月 19, 2025にアクセス、 https://developer.mozilla.org/en-US/docs/Web/Performance/How_browsers_work
- Houdini API – MDN Web Docs, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Web/API/Houdini_APIs
- 使用Fetch – Web API | MDN, 4月 19, 2025にアクセス、 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
- 从服务器获取数据- 学习Web 开发| MDN, 4月 19, 2025にアクセス、 https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Core/Scripting/Network_requests
- Fetch API – MDN Web Docs, 4月 19, 2025にアクセス、 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API
- 同期と非同期のリクエスト – Web API | MDN, 4月 19, 2025にアクセス、 https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest_API/Synchronous_and_Asynchronous_Requests
- シーケンス図とは?構成要素、書き方やメリットなどを活用例で …, 4月 19, 2025にアクセス、 https://www.lucidchart.com/pages/ja/tutorial/uml-sequence-diagram
- シーケンス図とは?書き方やツールを初心者でも分かるように紹介 – Cacoo, 4月 19, 2025にアクセス、 https://cacoo.com/ja/blog/what-is-sequence-diagram/