- ブラウザURL入力今ここ
- DNS名前→IP今ここ
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理今ここ
- 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つに区切って端から端まで追います。
- ・「7つ」は本コースの区切りであって、規格の区切りではない
- ・継ぎ目ごとに仕様が違う。切り分けで開く文書もそこで変わる
実物で見る、前半の3つ
継ぎ目の前半は curl で観測できます。上のサーバに curl -v を掛けた出力です(検証時はポート 3000 が別プロセスに使われていたため 3999 で取得した。以下、ポート番号だけが実測と異なる)。
* 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 も発生しません。
一方、バイト列を受け取った後は同じです。
<html><head></head><body><h1>Hello</h1></body></html>
書いていない html・head・body が木には存在し、要素は4つです。この補完の規則は次のレッスン以降で扱います。
「7つの継ぎ目」という区切りについて、最も正確なのはどれですか。
http://localhost:3000/ で開く
URL の分解、名前解決、接続、HTTPのやりとりを経てバイト列が届き、そこから木・箱・ピクセルへ進みます。7つがすべて通ります。
継ぎ目 通るか 観測手段① URLの分解 通る new URL()② 名前→アドレス 通る curl -v の resolved 行③ TCP接続 通る curl -v の Connected 行④⑤ HTTP 通る curl -v の > と < の行⑥⑦ 木・箱・画素 通る 開発者ツール
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 を抜いたものです。中間段が増えても継ぎ目の考え方は変わりません。
サーバ側の役割分担は「サーバーのしくみ」、ブラウザ内部の構造は「ブラウザ・エンジン」のクイズ群でも扱っています。本コースが問うのは「その表現は、どの継ぎ目で作り直されたのか」だけです。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
「継ぎ目ごとに担当する仕様が違う」ことが、切り分けにとって重要なのはなぜですか。
用語集(4語)
- 継ぎ目
- 本コースの用語。ある表現(文字列・名前・バイト列・木など)が別の表現に変わる境目。規格の節の区切りとは一致しない。
- scheme
- URL の先頭、`:` の前の部分。`http`・`https`・`file` など。この値で以降の処理経路が分かれる。
- DOM
- HTML のバイト列から作られる木構造。ブラウザが扱うのはこの木であって、元の文字列ではない。
- Living Standard
- WHATWG の仕様の形式。版番号を持たず更新され続けるため、参照時は取得日を添える。