Webフレームワークにおけるページが表示されるまでの仕組みを、文系出身が解説してみた

## はじめに

Webフレームワークを使ってWebサイトを開発していると、「ユーザーがURLを打ち込んだとき、裏では何が起きているの？」と気になったことはありませんか？私はこれまでいくつかのWebフレームワークを使用して開発してきたものの、少し前までその疑問に対してうまく説明できませんでした。この記事では、ネットワークの流れからアプリケーション処理までを文系出身にも分かるように説明したいと思います。
※Webフレームワークに関する内容だけでなく、ネットワークの基礎的な内容も含んでいます。

せっかくなので、Laravel（PHP）、Django（Python）、Spring Boot（Java）という代表的な3つのWebフレームワークを比較しながら、URLが入力されてからページが表示されるまでの裏側を追っていきます。


### 自己紹介

* 商学部出身
* 兵庫の情報系大学院生（27卒予定）
* サーバーサイド大好き人間
* 趣味はハッカソン
* バックエンドエンジニア志望
* 長期インターンにてSpring Bootを使用（半年以上）


## 第0章 ： Webページが表示されるまでの全体像

### 全体の流れ

```
[1] ユーザーがブラウザにURLを入力（URL解析）
 ↓
[2] ブラウザがキャッシュを確認（DNSキャッシュ / HTTPキャッシュ）
 ↓
[3] キャッシュがなければDNSサーバーに問い合わせ（ドメイン → IPアドレス変換）
 ↓
[4] TCP接続を確立（IPアドレス + ポート番号）
 ↓
[5] HTTPSリクエストを送信（暗号化通信）
 ↓
[6] ロードバランサーで最適なサーバーに振り分け
 ↓
[7] Webサーバー（Nginx / Apache）が受信
 ├─ 静的ファイルなら直接返却（画像/HTML/CSSなど）
 └─ 動的処理はアプリケーションに転送（FastCGI, WSGIなど）
 ↓
[8] Webアプリケーションが受信（Laravel / Django / Spring Boot）
 ├─ ルーティング処理（URLからControllerを決定）
 ├─ Controllerがリクエストを受け取り、Modelを呼び出す
 ├─ Modelがデータベースにアクセス
 └─ Viewテンプレートを使ってHTMLを生成
 ↓
[9] アプリケーションからHTMLをHTTPレスポンスとして返す
 ↓
[10] ブラウザがHTMLを受信
 ├─ HTMLをパース
 ├─ 追加でCSS/JS/画像などを取得
 └─ 画面をレンダリング
```

本記事では、上記10段階の流れを章に分けて説明していきます。


## 第1章：ユーザーがブラウザにURLを入力

ブラウザに `https://example.com/users/1`と打ち込むことは、このサイトの、このページが見たい」というお願い（リクエスト）をしています。URLには、インターネットの『住所』や『どのページか』などの情報が詰まっています。このURLはブラウザよって以下のように解析されます。

* `https` → スキーム：パソコンとサーバーがどの方法でアクセスするかを決めたルール
* `example.com` → ドメイン：サイトのインターネット上の住所
* `/users/1` → パス：サイト中のページの場所

### ※URLの構成要素
| 構成要素           | 名称    | 説明 |
| ----------------- | ------- | ---- |
| `https` | スキーム | パソコンとサーバーがどの方法でアクセスするかを決めたルール。`https`は、やり取りの内容が途中で見られたり書き換えられたりしないように、暗号で守られた通信を行う仕組み。 |
| `example.com` | ドメイン   | インターネット上のサイトの住所。人が覚えやすいように `example.com` のような文字列を使うが、コンピュータは後でこれを数字（IPアドレス）に変換してアクセスする（※詳細は第2章）。|
| `:443`        | ポート番号 | サーバーの中の部屋番号（httpsなら443番、httpなら80番）。その番号を指定して「どの部屋（アプリ）に用事があるか」を伝える（※詳細は第4章）。 |
| `/users/1`    | パス      | サイト中のページの場所。`/users/1` なら「ユーザー一覧の中の1番の人を見せて」とお願いしていることになる。サーバー側ではこのパスを見て、どの処理を動かすかを決める。 |
| `?q=test`     | クエリ    | サイトに対して「こんな条件で見せて」と細かいお願いを追加する部分。`?q=test` なら「検索のキーワードは `test` です」という意味。サーバー側ではこの値を取り出して処理する。 |


## 第2章：ブラウザがキャッシュを確認

ブラウザは、前に開いたことがあるページなら、その内容を一時的に保存（キャッシュ）しています。これは、もう一度見るときに早く表示するための工夫です。

- **DNSキャッシュ**
`example.com` のようなドメイン名を、コンピュータがわかる「IPアドレス」（e.g. 93.184.216.34）に変える必要があるが（詳細は第3章）、毎回調べていると時間がかかるので、一度調べた結果を一時的にブラウザ、OS、ルーターの中に保存しておく
- **HTTPキャッシュ**
ページの内容（HTML、画像、スタイル（CSS）、ボタンの動き（Javascript）など）を一時的にパソコンのメモリ・ディスクの中に保存しておく

もしキャッシュがあれば、それを使って一瞬でページが表示できます。DNSキャッシュがなければ「コンピューターがわかるサイトの場所（IPアドレス）」を調べ直し、HTTPキャッシュがなければインターネットを通じてもう一度サーバーへ取りに行きます。

### ※キャッシュ期限（TTL）の設定
キャッシュの保存期限はサイト側が設定していて、期限が切れるともう一度サーバーに聞き直します。
| 方法         | 説明      | ブラウザの動き   | サーバーとの通信  |
| ------------ | -------- | --------------- | -----------------|
| `Cache-Control: max-age=秒数` | キャッシュの保存期限を指示      | 期限内ならキャッシュをそのまま使う   | 通信なし（インターネットを通さない）                      |
| `ETag`            | ページのバージョン（ID）の変更を確認    | サーバーに「ページはこのIDのままでいい？」と聞く | 変更なければ `304 Not Modified` が返される |
| `Last-Modified`             | ページの最終更新日時の変更を確認             | サーバーに「ページはこの日から変わった？」と聞く  | 変更なければ `304 Not Modified` が返される              |
| `Cache-Control: no-cache`   | キャッシュを使う際に毎回サーバーに確認するように指示 | サーバーに「このキャッシュまだ使っていい？」と毎回聞く    | 軽い通信（ヘッダーだけのリクエスト）   |
| `Cache-Control: no-store`   | キャッシュの禁止を指示           | 毎回サーバーからまっさらなページを読み込む           | 毎回フル通信（ページ全体のリクエスト）      |


## 第3章：DNSサーバーでIPアドレスを取得

DNSは、人が読める名前（ドメイン）を、コンピュータが理解できる数字（IPアドレス）に変換する仕組みです。たとえば、ブラウザがDNSサーバーに「example.comのIPアドレスを教えて」と尋ねると、DNSサーバーが「192.0.2.10」と返してくれます。

DNSは「電話帳」と例えられることも多いですが、ドメイン名とIPアドレスの対応表を持っており、それを基にドメイン名 → IPアドレス変換をしています。

### ※DNSの動き
DNSリゾルバと呼ばれるエージェントが以下の順番でいくつかのDNSサーバーを順番にたどり、IPアドレスを探しています。
1. ルートDNSサーバー
2. トップレベルドメイン（.comなど）DNSサーバー
3. example.comを管理している権威DNSサーバー  

このように、DNSの裏側では階層的な仕組みが働いています。バトンをつなぐように何段階かのサーバーを通って、目的のIPアドレスを見つけます。ただし多くの場合、IPアドレス変換の高速化を目的として、途中の結果はキャッシュ（DNSキャッシュ）されるため、毎回すべてをたどる必要はありません。  


## 第4章：TCP接続を確立（ポート番号でアプリを指定）

DNSで目的のサイトの住所（IPアドレス）がわかったら、次はその相手と会話を始めるための回線をつなぎます。この回線を張る作業がTCP接続の確立です。このTCP接続が完了してはじめて、HTTPSリクエストを送れる状態になります。

TCPは、「通信の順番がズレないように」「途中でデータが消えないように」しっかり管理してくれる、安全な道路のようなものです。

ただし、住所（IPアドレス）だけではまだ足りません。その家の「どの部屋（アプリ）」に行くのかも決める必要があります。その「部屋（アプリ）の指定」こそがポート番号です。ポート番号には以下のようなものがあります。
- 80番ポート → HTTP（普通のWebページ）
- 443番ポート → HTTPS（暗号化された安全なWebページ）
- 25番ポート → メール送信
- 22番ポート → SSH（サーバー遠隔操作）

### ※3ウェイハンドシェイク
安全に会話を始めるために、TCPではいきなりデータを送りません。「ちゃんとつながるか」を確認する手順があります。それが「3ウェイハンドシェイク」と呼ばれるやりとりです。
1. クライアント → サーバー：「つなぎたいです！」
2. サーバー → クライアント：「OK！つなぎますよ！」
3. クライアント → サーバー：「了解、つなぎます！」  

この3回のやりとりで、「安全にデータを送り始められる状態」になります。

## 第5章：HTTPSでリクエストを送信

HTTPSは、安全に通信するために暗号化をします。通信内容を暗号化することで、3つのセキュリティ要素を提供します。

| セキュリティ要素 | 内容                             |
| -------- | ------------------------------ |
| **機密性**  | 通信内容を第三者に読まれないようにする（盗聴対策）      |
| **完全性**  | 通信内容が途中で書き換えられていないことを保証する（改ざん防止） |
| **認証**   | 通信相手が本物のサーバーであることを保証する（なりすまし防止）  |

### ※TLSハンドシェイク
HTTPSは、TLSという暗号化のルールを使って、HTTP通信をカプセル化しています（HTTP ＋ TLS）。安全な通信を実現するために、サーバーとクライアントが暗号化のための情報を安全に交換し合うプロセスを「TLSハンドシェイク」と呼びます。

1. **Client Hello**
ブラウザがサーバーに対してサポートするTLSのバージョン、暗号方式の組み合わせ（暗号スイート）、乱数（nonce）などを送る
2. **Server Hello**
サーバーがTLSバージョンと暗号スイートを選択し、デジタル証明書を送る
3. **証明書検証**
ブラウザは証明書の発行元（CA）を確認し、本物のサーバーかをチェックする
4. **セッション鍵の交換**
Diffie-HellmanやRSAを用いて、セッション鍵を安全に共有する
5. **Finished（通信開始）**
双方が暗号通信の準備が整ったことを確認し合う

これにより、以降のHTTP通信は暗号化されたセッション鍵によって守られます。


## 第6章：ロードバランサーでサーバーを振り分け

Webサービスへのアクセスが増えると、1台のサーバーでは対応しきれなくなります。そこで登場するのが「ロードバランサー」です。簡単に言えば、複数のサーバーに処理を割り振る交通整理係です。
```
[ユーザー]
   ↓
[ロードバランサー] ←→ [サーバーA]
    　　　　　　　　　[サーバーB]
    　　　　　　　　　[サーバーC]
```
Webサービスの運用を安定・効率化する上で、ロードバランサーは次の3点において非常に有用です。
1. **スケーラビリティ**
複数のWebサーバーでアクセスを分散することで、高負荷に耐えられるようになる。
2. **可用性**
サーバーが1台落ちても、他のサーバーでサービスを継続できる（フェイルオーバー）。
3. **柔軟な運用**
バックエンドをメンテナンスする間も、ユーザーに影響を与えず段階的なデプロイが可能（Blue-Green Deployment など）。

### ※ロードバランサーの仕組み
ロードバランサーは、受け取ったリクエストを以下のようなアルゴリズムで各サーバーに振り分けます。

| アルゴリズム          | 説明                                      |
| --------------- | --------------------------------------- |
| **ラウンドロビン**     | サーバーに順番にリクエストを回していく                     |
| **最小接続数**       | 現在もっとも接続が少ないサーバーに振り分ける                  |
| **IPハッシュ**      | クライアントIPのハッシュ値によって振り分け先を固定化（セッション維持に有効） |
| **重み付きラウンドロビン** | サーバーごとに能力に応じた重みを設定し、処理能力に応じて振り分ける       |

### ※L4ロードバランサー vs L7ロードバランサー
| 項目       | L4 ロードバランサー                 | L7 ロードバランサー                      |
| -------- | --------------------------- | -------------------------------- |
| 処理する階層   | トランスポート層（OSI第4層）            | アプリケーション層（OSI第7層）                |
| 振り分け方法   | IPアドレスとポート番号、プロトコル（TCP/UDP） | URLパス、HTTPヘッダー、Cookie、クエリパラメータなど |
| 処理内容     | セッション単位の単純な負荷分散             | コンテンツに基づく高度なルーティングやポリシー制御        |
| 柔軟性      | 低い                          | 高い                               |
| 対応プロトコル  | TCP, UDP など                 | HTTP, HTTPS など                   |
| 主な用途     | Webサーバーのシンプルな分散、ゲーム通信など     | Webアプリのルーティング制御、APIゲートウェイ、ABテスト等 |


## 第7章：Webサーバーがリクエストを受け取る

Webサーバー（NginxやApache）は、ブラウザからのリクエストを受け取ります。ここで「これは自分で処理すべきか？アプリに回すべきか？」を判断します。

- 静的リソース（HTML, CSS, JS, 画像など）
    - `/assets/logo.png` や `/styles/main.css` のようなリクエストは、Webサーバーが直接ファイルシステムから読み取ってレスポンス
    - ファイルキャッシュ（ブラウザキャッシュやCache-Control）を使うことで表示速度が向上
- 動的リソース（APIやアプリのルーティング対象）
    - `/users/123` のようなリクエストは、アプリケーションにリバースプロキシ経由で転送
    - WebサーバーはHTTPヘッダーやパスを見て、動的処理が必要か判断する

Webサーバーは、自分で対応できるか判断して、できなければアプリケーションにバトンタッチします。

### ※アプリへのバトンタッチ方法
以下はそれぞれのフレームワークにおける一般的な構成です。
* Laravel → Apache/Nginx → PHP-FPM（FastCGI）
* Django → Nginx → Gunicorn（WSGI）
* Spring Boot → JVM（Webサーバー内蔵（Tomcat）なので単独で受けられる）


## 第8章：アプリケーションが処理を実行

ここからが Laravel / Django / Spring Boot の出番で、Webアプリケーションの本体です。サーバーサイドでは、MVC（Model-View-Controller）アーキテクチャに基づいて、動的な処理が進行します。

1. **ルーティング**：URLを見て、「誰が担当するか（Controller）」を決める
2. **Controller**：リクエスト内容を確認して、処理を行う（e.g. ログイン確認したい → 認証、外部の機能を使いたい → 外部API呼び出し、データが欲しい → Model呼び出し）
3. **Model**：データベースにアクセスして情報を取得
4. **View**：データをもとにHTMLを作成

このように、アプリが協力して必要なデータを使ってページを作り上げます。

### ※Laravel / Django / Spring Boot の処理手順

#### Laravelの処理手順（PHP）
1. すべてのHTTPリクエストは `public/index.php` にルーティングされる
2. `routes/web.php` や `routes/api.php` でルーティング定義
3. Controllerが呼び出され、Model（Eloquent ORM）を介してDBアクセス
4. 取得したデータをBladeテンプレートに渡してHTMLを生成

#### Djangoの処理手順（Python）
1. `urls.py` にURLとView関数（またはクラス）をマッピング
2. View関数（FBVまたはCBV）でリクエスト内容を処理し、Model（Django ORM）を操作
3. テンプレート（Django Template Language）にデータを渡し、HTMLを生成

#### Spring Bootの処理手順（Java）
1. `DispatcherServlet` がすべてのリクエストをフロントで受け取る
2. アノテーション（`@GetMapping`, `@PostMapping`など）でControllerメソッドにマッピング
※`@RestController` にするとHTMLではなくJSONが返る（API）
3. Controller → Service → Repository でDB操作
※Service：ビジネスロジック
※Repository：データアクセス（Spring Data JPA）
4. ControllerでView名を返すことで、ViewResolver（Thymeleafなど）がHTMLを生成

※Laravel / Django は、Service層（ビジネスロジック）がデフォルトでは存在しない

## 第9章：HTMLとしてレスポンスを返す

アプリケーションが作ったHTMLを、Webサーバー経由でブラウザに送り返します。これを「HTTPレスポンス」と呼びます。

### ※それぞれのフレームワークにおけるレスポンス形式

| 種別        | Laravel                            | Django                        | Spring Boot                    |
| --------- | ---------------------------------- | ----------------------------- | ------------------------------ |
| HTML View | `return view('users.show', [...])` | `return render(request, ...)` | `return "users/show"`          |
| JSON API  | `return response()->json($data)`   | `return JsonResponse(data)`   | `@ResponseBody return UserDto` |
| リダイレクト    | `redirect()->route('home')`        | `redirect('home')`            | `return "redirect:/home"`      |


## 第10章：ブラウザが画面を描画

レスポンスとして届いたHTML/CSS/JSを、ブラウザが画面として描画（レンダリング）します。

### ※ブラウザ内部の処理ステップ
1. HTMLをパース → DOMツリー構築（構造を作る）
2. CSSの適用 → スタイルツリー構築（見た目を整える）
3. JS実行 → DOM操作やイベント処理（動きをつける）
4. レイアウト計算・ペイント・合成
5. 画面に表示（レンダリング）


## まとめ
このように、URLを入力してからページが表示されるまでには、Webフレームワークの処理範囲を超えた裏側のやり取りが存在します。こうした仕組みを理解することは、Webフレームワークを用いた開発だけでなく、AWSなどのクラウド技術を学ぶ上でも非常に重要だと感じました。質問や改善のフィードバックがあれば、ぜひコメントで教えてください！

## 引用
- <a href='https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8BWeb%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%B0%8F%E6%9E%97-%E6%81%AD%E5%B9%B3/dp/4797388811'>イラスト図解式この一冊で全部わかるWeb技術の基本</a>
- <a href='https://developer.mozilla.org/ja/docs/Web/HTTP/Overview'>HTTP の概要 - MDN Web Docs - Mozilla</a>
- <a href='https://zenn.dev/airiswim/articles/71cfd48cba418b'>webの基礎：HTTP通信の仕組み / ホスティングとドメインの関係性</a>
- <a href='https://zenn.dev/airiswim/articles/71cfd48cba418b'>URLを構成する5つの要素：「サブドメイン」や「サブディレクトリ」の意味を解説</a>
- <a href='https://shukapin.com/infographicIT/url'>【図解】URLの定義と構成</a>
- <a href='https://www.onamae.com/column/domain/35/'> DNSキャッシュの役割とは？仕組みとキャッシュクリアの方法を徹底解説！</a>
- <a href='MDN Web Docshttps://developer.mozilla.orgHTTP キャッシュ - MDN Web Docs’> HTTP キャッシュ - MDN Web Docs</a>
- <a href='https://zenn.dev/mesi/articles/e218457fc6c52e'>ブラウザキャッシュの仕組みについてまとめた</a>
- <a href='https://www.ibm.com/jp-ja/topics/time-to-live'>Time to Live（TTL）とは </a>
- <a href='https://www.cloudflare.com/ja-jp/learning/dns/what-is-1.1.1.1/'> 1.1.1.1 とは？DNSリゾルバーとは？</a>
- <a href='https://www.cloudflare.com/learning/dns/dns-server-types/'> DNSサーバーの種類</a>
- <a href='https://www.itmanage.co.jp/column/tcp-ip-protocol/'>TCP/IPとは？通信プロトコルの階層モデルを図解で解説</a>
- <a href='https://qiita.com/tatsuya4150/items/ae4d5e95e43ce0670bc0'> 【TCP】コネクションの確立までの道のり</a>
- <a href='https://techgrowup.net/security-handshake'>TCP 3ウェイハンドシェイクプロセスの解説：安定通信の基盤を理解する</a>
- <a href='https://www.cloudflare.com/ja-jp/learning/ssl/what-happens-in-a-tls-handshake/'>TLS | SSLハンドシェイクのプロセスは？</a>
- <a href='https://qiita.com/kurokoya/items/2ebd7abd5e16522b205f'> 【暗号技術整理】共通鍵暗号・公開鍵暗号・鍵交換・RSA・AES・DHの関係を理解する</a>
- <a href='https://it-trend.jp/server_application_management/article/114-0008'>ロードバランサーの基本がマルわかり！仕組みから主要機能まで解説</a>
- <a href='https://zenn.dev/axpensive/articles/d80e4d102eefb4'>L4とL7ロードバランサーの違い</a>
- <a href='https://zenn.dev/azunyan/articles/0dad881616063b'> 【入門】 Nginx + PHP-FPM の仕組み</a>
- <a href='https://note.com/ymtk00/n/nd4aad63c3929'>Djangoを使ったWebアプリの作り方⑤Docker+Nginx+Gunicorn編</a>
- <a href='https://dexall.co.jp/articles/?p=331'> Spring BootとTomcatの完全ガイド：初心者から本番環境まで押さえるべき7つのポイント</a>
- <a href="https://zenn.dev/oreo2990/articles/280d39a45c203e">Webブラウザのレンダリングの仕組みを理解する</a>
- <a href="https://developer.mozilla.org/ja/docs/Glossary/Parse">Parse (構文解析) - MDN Web Docs 用語集</a>