Dev Study
← 1行のHTMLが画面に出るまで
レッスン 1 / 8·約 9 分·導線 1行のHTMLが画面に出るまで

何を追うのか — ファイルが「表示」に変わる7つの継ぎ目

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力今ここ
  2. DNS名前→IP今ここ
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理今ここ
  7. DB保存

localhost で自分のサーバを開くとき、ルータ・ロードバランサ・Nginx・DB は通りません。第27週で描く地図から中間段を抜いた最短の線を追います。

まず結論

画面に出た Hello は、`index.html` の中身がそのまま運ばれたものではありません。文字列 → 名前 → 接続 → バイト列 → 木 → 箱 → ピクセル、と継ぎ目ごとに作り直された結果です。

しかも継ぎ目ごとに担当する仕様が違います。URL Standard、RFC 6761、RFC 9112、RFC 9110、HTML Standard——別々の文書が別々の区間を規定するので、切り分けも継ぎ目単位になります。

? 読む前に予測

同じ `index.html` を `file:///…/index.html` と `http://localhost:3000/` で開きます。違いはどこにあるでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

「ファイルを表示する」という言い方が隠しているもの

このコースでは、たった1行のファイルを1つだけ扱います。

<h1>Hello</h1>

index.html はこの14バイトだけで、<!DOCTYPE html> も <html> も <head> も <body> もありません。これを次のサーバで配ります。

const http = require("http");
const fs = require("fs");
http.createServer((req, res) => {
  res.end(fs.readFileSync("index.html"));
}).listen(3000);

http://localhost:3000/ を開くと画面に Hello が出ます。これを普段「ファイルを表示した」と呼びます。

しかしその中では、同じ内容が何度も別の形に作り直されています。打った文字列は構造に分解され、名前はアドレスになり、アドレスは接続になり、接続の上をバイト列が流れ、バイト列は木になり、木は箱の配置になり、箱はピクセルになります。どの段も前の段のものをそのまま渡しません。

本コースはこの境目を継ぎ目と呼び、7つに区切って端から端まで追います。

1行のHTMLが画面に出るまでの7つの継ぎ目(本コースの区切り)
① 文字列 → URL の構造URL Standard
ホスト名を取り出す
② 名前 → アドレスRFC 6761(localhost の特別扱い)
宛先が決まる
③ アドレス → TCP接続RFC 9293
運ぶ道ができる
④ 要求 → バイト列RFC 9112(メッセージの形)
サーバが応答を作る
⑤ 応答 → 意味づけRFC 9110 / MIME Sniffing
本文が手に入る
⑥ バイト列 → 木(DOM)HTML Standard
構造が決まる
⑦ 木 → 箱 → ピクセルHTML Standard §8.1.7
  • ・「7つ」は本コースの区切りであって、規格の区切りではない
  • ・継ぎ目ごとに仕様が違う。切り分けで開く文書もそこで変わる
具体実物

実物で見る、前半の3つ

継ぎ目の前半は curl で観測できます。上のサーバに curl -v を掛けた出力です(検証時はポート 3000 が別プロセスに使われていたため 3999 で取得した。以下、ポート番号だけが実測と異なる)。

curl -v http://localhost:3000/(実機出力。進捗メータの行は省略)コマンド出力
* Host localhost:3000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:3000...
* Connected to localhost (::1) port 3000
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Wed, 16 Sep 2026 02:15:52 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Content-Length: 14
<
<h1>Hello</h1>

この出力に継ぎ目の②〜⑤が並んでいます。was resolved が名前がアドレスになったところ、Connected to が接続できたところ、> が送ったバイト列、< が返ってきたバイト列です。

注目したいのは応答に Content-Type が無いことです。付いたヘッダは Date・Connection・Keep-Alive・Content-Length の4つだけ。「何の形式か」をサーバは一度も言っていないのに、ブラウザでは見出しとして表示されます。誰が型を決めたのかは⑤の話で、次のレッスン以降です。

そして curl に見えるのはここまでです。⑥以降はこの出力に現れません。

✓ ここまでの確認

サーバが返したのは `<h1>Hello</h1>` の14バイトだけです。それでも画面には見出しが出ます。この間に何が起きていますか。

抽象原理

継ぎ目が変換であるかぎり、症状は継ぎ目に張り付く

継ぎ目を分けるのは暗記のためではありません。表現が変わる場所でしか、表現の壊れ方は生じないからです。

  • URL が思ったとおりに分解されない → ①(URL Standard)
  • 名前が意図した先に向かわない → ②(名前解決)
  • 接続そのものができない → ③(TCP)
  • リクエストの形が受け付けられない → ④(RFC 9112)
  • 届いてはいるが扱われ方が違う → ⑤(RFC 9110 と型の判定)
  • 書いたとおりの構造にならない → ⑥(HTML のパース)
  • 構造は正しいのに見た目が違う → ⑦(配置と描画)

観測手段も継ぎ目ごとに変わります。 ①は new URL() で分かり、②③④⑤は curl -v や生のバイト列で見え、⑥⑦は開発者ツールでしか見えません。

具体実物

前半が無い経路 — file:// で開く

同じ index.html をサーバ無しで file:///…/index.html として開いても画面には同じ Hello が出ます。ただし通った継ぎ目は違います。

Fetch Standard §4.3 Scheme fetch は scheme ごとに処理を分岐させ、HTTP へ進むのは HTTP(S) scheme——http と https ——だけです。file については、この規格はこう書いています。

つまり Fetch Standard は file: の中身を規定していません。読者への演習だと書いてあります。言えるのは「実装がどう読むかは規格の外」であり、HTTP fetch の分岐には入らないことです。名前解決も接続も HTTP も発生しません。

一方、バイト列を受け取った後は同じです。

DOMParser で <h1>Hello</h1> をパースした結果(Chrome 152 / macOS、2026-09-16)コマンド出力
<html><head></head><body><h1>Hello</h1></body></html>

書いていない html・head・body が木には存在し、要素は4つです。この補完の規則は次のレッスン以降で扱います。

✓ ここまでの確認

「7つの継ぎ目」という区切りについて、最も正確なのはどれですか。

⇄ 2つを見比べる
具体例 A

http://localhost:3000/ で開く

URL の分解、名前解決、接続、HTTPのやりとりを経てバイト列が届き、そこから木・箱・ピクセルへ進みます。7つがすべて通ります。

通る継ぎ目と、観測できる場所表
継ぎ目 通るか 観測手段
① URLの分解 通る new URL()
② 名前→アドレス 通る curl -v の resolved 行
③ TCP接続 通る curl -v の Connected 行
④⑤ HTTP 通る curl -v の > と < の行
⑥⑦ 木・箱・画素 通る 開発者ツール
具体例 B

file:///…/index.html で開く

Fetch Standard は scheme で分岐し、HTTP へ進むのは http / https だけです。file はその分岐に入らず、名前解決も接続もHTTPも起きません。それでも画面には同じ Hello が出ます。

通る継ぎ目と、観測できる場所表
継ぎ目 通るか 観測手段
① URLの分解 通る new URL()
② 名前→アドレス 通らない ―
③ TCP接続 通らない ―
④⑤ HTTP 通らない ―
⑥⑦ 木・箱・画素 通る 開発者ツール

同じファイルで、画面に出るものも同じです。それなのに切り分けの手がかりは大きく違います。なぜでしょうか。

「画面に Hello が出た」という観測が、それぞれの経路で何を保証しているか比べてみてください。

この章のまとめ

  • 画面に出た Hello はファイルの中身そのものではない。文字列 → 名前 → 接続 → バイト列 → 木 → 箱 → ピクセルと継ぎ目ごとに作り直された結果。
  • 継ぎ目ごとに担当する仕様が違う(URL Standard / RFC 6761 / RFC 9112 / RFC 9110 / HTML Standard …)。開く文書も観測手段も変わる。
  • 「7つ」は本コースの区切りで、規格の区切りではない。 意味があるのは数ではなく線の位置。
  • curl -v に見えるのは②〜⑤まで。⑥⑦は開発者ツールでしか見えない。1つの観測器で全部は見えない。
  • file:// は Fetch Standard の HTTP の分岐に入らず、名前・接続・HTTP が無い。同じ画面でも確かめられた範囲は違う。
具体実物

この先の学びにどう繋がるか

次のレッスン『URLを打つ — :80 が消える理由』から、継ぎ目を1つずつ順に開いていきます。①の URL の分解、②の名前解決、③④の接続とリクエスト、⑤の応答の型、⑥の木、⑦の描画、そして <script> が⑥に割り込む話まで、この7つが本コースの骨格です。

ここで扱ったのは localhost の最短経路です。実際の Web にはこの線の途中にさらに多くの段が挟まり、その全体像は第27週『リクエストは何段の手を経るのか — 全体地図』で扱います。本コースの線は、あの地図からルータ・ロードバランサ・Nginx・DB を抜いたものです。中間段が増えても継ぎ目の考え方は変わりません。

サーバ側の役割分担は「サーバーのしくみ」、ブラウザ内部の構造は「ブラウザ・エンジン」のクイズ群でも扱っています。本コースが問うのは「その表現は、どの継ぎ目で作り直されたのか」だけです。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

「継ぎ目ごとに担当する仕様が違う」ことが、切り分けにとって重要なのはなぜですか。

用語集(4語)
継ぎ目
本コースの用語。ある表現(文字列・名前・バイト列・木など)が別の表現に変わる境目。規格の節の区切りとは一致しない。
scheme
URL の先頭、`:` の前の部分。`http`・`https`・`file` など。この値で以降の処理経路が分かれる。
DOM
HTML のバイト列から作られる木構造。ブラウザが扱うのはこの木であって、元の文字列ではない。
Living Standard
WHATWG の仕様の形式。版番号を持たず更新され続けるため、参照時は取得日を添える。