本文へ移動

ホーム / Web / 第2部 Web の基礎

第2部 Web の基礎・第2章

HTTP とブラウザ

★★★ 必須12トピック・面接 5問

Web の土台となる HTTP の仕組みと、ブラウザの中で何が起きているかを押さえる。

別のページで開く →

ネットワーク図を読み込んでいます…

ひとことで

リクエスト(メソッド・URL・ヘッダー・本文)とレスポンス(ステータス・ヘッダー・本文)の決まった形のやりとり。

HTTP は、ブラウザ(クライアント)がサーバーにリクエストを送り、サーバーがレスポンスを返すやりとりの決まりです。リクエストは「メソッド・URL・ヘッダー・本文」、レスポンスは「ステータスコード・ヘッダー・本文」でできています。

リクエストとレスポンス、ステータスの4つの範囲ブラウザクライアントサーバーGET /api/users/42 HTTP/1.1ヘッダー:Host・Accept・Authorization・Cookie本文:GET はなし(POST・PUT は JSON など)HTTP/1.1 200 OKヘッダー:Content-Type・Cache-Control・Set-Cookie本文:JSON・HTML など2xx 成功200・201・2043xx 移動・キャッシュ301・304・3084xx クライアントが直す400・401・403・404・4225xx サーバーが直す500・503
リクエストとレスポンスの形と、ステータスコードの範囲
GET /api/users/42 HTTP/1.1
Host: example.com
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{"id":42,"name":"Sato"}

HTTP/1.1 はこのとおりテキストで送り、HTTP/2・3 は同じ意味の内容をバイナリのフレームにして送ります。どの版でも「メソッド・URL・ヘッダー・本文」と「ステータス・ヘッダー・本文」という形は同じなので、まずこの形を読めるようにします。開発者ツールの Network タブで、実際のリクエストとレスポンスのヘッダーを見るのが一番の練習です。

HTTP キャッシュ

面接ではこう答える

HTTP は、クライアントがリクエストを送り、サーバーがレスポンスを返すやりとりの決まりです。リクエストはメソッド、URL、ヘッダー、本文、レスポンスはステータスコード、ヘッダー、本文でできています。HTTP 自体は前のリクエストを覚えていないので、ログイン状態は Cookie やトークンで毎回伝えます。HTTP/2 や3でも、この形の意味は変わりません。

2.2メソッドと冪等性

用語★★★ 必須
ひとことで

安全=サーバーの状態を変えない、冪等=何回送っても結果が同じ。GET は両方、PUT・DELETE は冪等、POST はどちらでもない。

「安全」と「冪等」で、リトライしてよいかが決まる安全・冪等・GET・HEAD・OPTIONS・サーバーを変えない・何度でも送ってよい冪等だが安全でない・PUT・DELETE・状態は変える・2回目も結果は同じどちらでもない・POST・PATCH・2回送ると2回起きる・冪等キーで守る
メソッドの3つのグループ

安全=サーバーの状態を変えない、冪等(べきとう)=何回送っても結果が同じ、という意味です。リトライしてよいかの判断に使います。

メソッド用途安全冪等
GET取得○○
POST作成・処理の実行××
PUT丸ごと置き換え×○
PATCH一部を更新××(作り方による)
DELETE削除×○

GET で削除や更新をしてはいけません。リンクの先読みやクローラーが勝手に GET を送るからです。

PUT は「この内容で丸ごと置き換える」ので、何回送っても同じ状態になります。PATCH は「1 増やす」のような書き方にすると冪等ではなくなります。

冪等性とリトライ

面接ではこう答える

HTTP のメソッドには「安全」と「冪等」という性質があります。安全は状態を変えないこと、冪等は何回送っても結果が1回分と同じになることです。GET は両方を満たすのでキャッシュやリトライが自由にでき、PUT と DELETE は冪等なのでリトライしても大丈夫です。POST は冪等ではないので、決済のような処理では冪等キーで二重実行を防ぎます。

ひとことで

4xx はクライアントが直す、5xx はサーバーが直す。正しいコードを返すと、監視・リトライ・キャッシュが正しく動く。

先頭の数字で、誰が直すかが分かる1xx 情報途中経過(101 で WebSocket へ)2xx 成功200・201・2043xx リダイレクト301・302・304・3084xx クライアント直すのは送った側5xx サーバー直すのはサーバー側
ステータスコードの5つの範囲
コード使う場面
200 OK成功して本文を返す
201 Created作成した。Location に新しい URL
204 No Content成功したが返す本文がない(削除など)
301 Moved Permanently恒久的な移転。検索エンジンも新 URL に移る(POST を保ちたいなら 308)
304 Not Modifiedキャッシュがまだ使える(本文なし)
400 Bad Request形式が壊れている(JSON が読めないなど)
401 Unauthorizedログインしていない・トークンが無効
403 Forbiddenログインはしているが権限がない
404 Not Foundない。権限がないことを隠したいときにも使う
409 Conflict状態がぶつかった(重複登録・版の競合)
422 Unprocessable Content形式は正しいが中身が不正(入力チェックの失敗)
429 Too Many Requests回数制限。Retry-After を付ける
500 Internal Server Errorサーバーのバグ・想定外の例外
503 Service Unavailable一時的に受けられない(メンテナンス・過負荷)

4xx は「クライアントが直す」、5xx は「サーバーが直す」です。エラーなのに 200 を返すと、監視やリトライの判断ができなくなります。

迷いやすいのは 401 と 403(ログインしていない/権限がない)と、400 と 422(形式が壊れている/中身が不正)です。チームで使い分けを決めて API 全体でそろえます。

面接ではこう答える

ステータスコードは先頭の数字で意味が分かれます。2xx は成功、3xx はリダイレクトやキャッシュの確認、4xx は送った側の問題、5xx はサーバー側の問題です。よく使い分けを聞かれるのは、ログインしていない 401 と権限がない 403、形式が壊れた 400 と中身が不正な 422 です。エラーなのに 200 を返すと、監視でもリトライの判断でも気づけなくなるので、正しいコードを返すようにしています。

ヘッダーは、本文とは別に付ける「付け札」です。役割ごとに覚えると整理しやすくなります。

役割リクエストレスポンス
形式Accept・Content-TypeContent-Type
認証Authorization・CookieSet-Cookie・WWW-Authenticate
キャッシュIf-None-Match・If-Modified-SinceCache-Control・ETag・Last-Modified
移動・場所-Location
CORSOriginAccess-Control-Allow-*
回数制限-Retry-After
調査用X-Request-Id・traceparent同じ ID を返す

押さえる要点

  • Content-Type:本文の形式(application/json など)。Accept:欲しい形式。
  • Authorization:認証情報(Bearer トークン)。Cookie / Set-Cookie:セッション。
  • Cache-Control・ETag・If-None-Match:キャッシュ。
  • Location:リダイレクト先・作成したリソースの URL。
  • Origin・Access-Control-Allow-Origin:CORS。

独自のヘッダーは X- を付けない名前が今は推奨されていますが、既存の X-Request-Id などはそのまま使われています。

2.5HTTP/1.1・HTTP/2・HTTP/3

用語★★☆ 重要
ひとことで

1本の接続で並行に送る(多重化)のが HTTP/2、パケット消失に強い UDP 上の QUIC を使うのが HTTP/3。

Web ページの表示の速さは、サーバーの処理だけでなく、HTML・CSS・JavaScript・画像といった何十ものファイルをどう運ぶかでも大きく変わります。HTTP の版の違いは、その運び方の違いです。

フロントエンドの性能改善で「昔の工夫(ドメインの分割・ファイルの結合)がまだ要るか」を判断するときや、面接の「HTTP/2 と HTTP/3 の違い」に答えるときに使います。

HTTP には大きく3つの版があり、中身(メソッド・ヘッダー・ステータス)の意味は同じで、運び方が違います。

同時にたくさん取るときの送り方HTTP/1.1:接続ごとに1つずつ接続1a.jsd.pngg.js接続2b.csse.pngh.png接続3c.jsf.png同時は数本まで。それ以上は前が終わるのを待つHTTP/2・HTTP/3:1本の接続で同時に接続1abcdabcdabcファイルを小さなフレームに分けて、1本の接続に混ぜて送る(多重化)HTTP/3 は QUIC で、失われた分だけを待てばよい
HTTP/1.1 と HTTP/2・3 の送り方の違い
項目HTTP/1.1HTTP/2HTTP/3
下の通信TCPTCPQUIC(UDP の上)
形式テキストバイナリのフレームバイナリのフレーム
同時に送る1本の接続で1つずつ。ブラウザは接続を6本程度まで張る1本の接続で多数を同時に(多重化)同じく多重化
ヘッダー毎回そのまま送る圧縮(HPACK)圧縮(QPACK)
パケットが失われたときその接続が止まるTCP の性質で全部のやりとりが待たされる失われたやりとりだけが待つ。接続の確立も速い

HTTP/1.1 の時代は、同時に取れるファイル数が少なかったので、ドメインを分けて接続数を増やしたり、画像を1枚に結合(CSS スプライト)したり、JS を1ファイルにまとめたりしました。HTTP/2 以降は1本の接続で多数のファイルを同時に取れるので、これらは不要になり、むしろドメインを分けると DNS・TLS のやり直しで遅くなります。今は CDN やロードバランサーで HTTP/2・HTTP/3 を有効にしておくのが普通です。

下の「ブラウザで試す」の図では、同じ画像6枚を読み込むときに、HTTP/1.1 が1本の接続で1つずつ送る様子、HTTP/2 が1本の TCP 接続の中で多重化する様子、パケットが1つ失われると全部のストリームが待たされる様子(TCP の HOL ブロッキング)、HTTP/3 が QUIC でストリームごとに独立して進む様子を、順に見られます。表の「パケットが失われたとき」の行を、3つ目と5つ目の手順で確かめてください。ブラウザが Alt-Svc ヘッダーで HTTP/3 が使えると知ってから QUIC でつなぎ直す点にも注目します。

面接ではこう答える

HTTP/1.1 は1本の接続で1つずつ送るので、ブラウザは接続を複数張っていました。HTTP/2 は1本の接続で多数のやりとりを同時に流す多重化とヘッダーの圧縮で速くしましたが、TCP の上なのでパケットが1つ失われると全部が待たされます。HTTP/3 は UDP の上の QUIC を使い、失われたやりとりだけが待つので、モバイルのような不安定な回線に強くなっています。

別のページで開く →

ネットワーク図を読み込んでいます…

2.6HTTP キャッシュ

用語★★★ 必須
ひとことで

Cache-Control と ETag で、ブラウザ・CDN がレスポンスを再利用する仕組み。

「デプロイしたのに古い画面のまま」「他人のマイページが表示された」は、どちらも HTTP キャッシュの指定が原因になりうる障害です。キャッシュは、うまく使えば表示を速くし、サーバーの負荷と転送の料金を減らしますが、指定を間違えると古い内容や他人の内容を配ってしまいます。

レスポンスごとに「どこに・どれだけの間保存してよいか」を決めるのは、サーバーを書く Web エンジニアです。

HTTP キャッシュは、一度取ったレスポンスをブラウザや CDN にとっておき、次は通信せずに(または軽い確認だけで)使う仕組みです。どう扱うかはサーバーが Cache-Control ヘッダーで指示します。

期限内は通信なし、切れたら「変わった?」と確かめるno-store は保存しない。no-cache は保存するが毎回「確かめる」へ進むリクエストキャッシュにある?期限内?max-age・s-maxageそのまま使う通信なしあるまだサーバーから取得200 と本文ない確かめるIf-None-Match: ETag切れた304 Not Modified本文なし・保存分を使う200 OK新しい本文に入れ替え同じ変わった
ブラウザがキャッシュを使うかどうか決める流れ
指定意味
max-age=秒その秒数のあいだは確認なしで使ってよい
no-cache保存してよいが、使う前に毎回サーバーに確認する(「キャッシュしない」ではない)
no-store保存しない。個人情報を含むレスポンス向け
privateブラウザだけが保存してよい。CDN など共有のキャッシュには置かない
public共有のキャッシュにも置いてよい
s-maxage=秒共有のキャッシュ(CDN)だけに効く max-age
immutable期限内は中身が変わらないので、再読み込みでも確認しない

期限が切れたあとの確認の仕組み(ETag と 304)と、長期キャッシュを安全にするファイル名の付け方は、次のトピックで説明します。

よくある失敗:ログイン中のユーザー向けのページに public を付けて CDN に保存され、他人に表示される事故があります。ユーザーごとに変わる内容は private か no-store にします。

SRE の「キャッシュ(HTTPキャッシュと多層キャッシュ)」

下の「ブラウザで試す」の図では、ハッシュ付きの名前の画像を CDN が S3 から取ってきて保存し、ブラウザも同じ Cache-Control に従って保存する様子、期限内はブラウザが通信せずにキャッシュを使う様子、ハッシュの付かないファイルを ETag で確かめて 304 が返る様子を、順に見られます。後半の「キャッシュしない応答」は、上の「よくある失敗」を private, no-store でどう防ぐかの手順です。

面接ではこう答える

HTTP キャッシュは、一度取ったレスポンスをブラウザや CDN にとっておき、次は通信せずに使う仕組みで、サーバーが Cache-Control ヘッダーで指示します。max-age の間は確認なしで使い、no-cache は保存してよいが毎回確認、no-store は保存しない、という意味です。private はブラウザだけ、public は CDN にも置いてよいという指定で、ログイン後のページに public を付けると他人に表示される事故につながります。

別のページで開く →

ネットワーク図を読み込んでいます…

ひとことで

ETag で「変わっていないか」だけを確かめて 304 で本文を省き、中身が変わるとファイル名も変わるハッシュで長期キャッシュする。

期限が切れても、変わっていなければ本文は送らないブラウザサーバーGET /app.css200 + ETag: "v1" + 本文(max-age が切れる)GET + If-None-Match: "v1"304 Not Modified(本文なし)
期限が切れたあとの確認(条件付きリクエスト)

304 と ETag

サーバーは中身の版を表す ETag(または Last-Modified)を返します。期限が切れたブラウザは If-None-Match: "その値" を付けて確認し、変わっていなければサーバーは本文なしの 304 Not Modified を返します。通信量が減ります。

ファイル名にハッシュを付けて長期キャッシュ

ビルドツールは app.3f9a1c.js のように、中身から作ったハッシュをファイル名に付けます。中身が変わると名前も変わるので、古いキャッシュを気にせず長く保存させられます。入口の HTML は短く(または毎回確認)します。

# JS・CSS・画像(ハッシュ付き)
Cache-Control: public, max-age=31536000, immutable
# HTML
Cache-Control: no-cache
# ログイン後の API
Cache-Control: private, no-store

この2つを組み合わせると、「ハッシュ付きの JS・CSS は1年キャッシュ」「HTML は毎回 ETag で確認」となり、デプロイ直後でも新しい HTML が新しいファイル名を指すので、古い画面が残りません。

面接ではこう答える

キャッシュの期限が切れたとき、ブラウザは前回もらった ETag を If-None-Match に付けて確認します。変わっていなければサーバーは本文なしの 304 を返すので、通信量が減ります。JS や CSS はファイル名に中身のハッシュを付けて1年などの長期キャッシュにし、入口の HTML は毎回確認にします。こうするとデプロイ後に古い画面が残る問題も起きません。

ひとことで

別オリジンへの読み取りはブラウザが止める。サーバーが許可ヘッダーを返したときだけ読める。

オリジンは「スキーム+ホスト+ポート」の組です(https://app.example.com:443)。ブラウザは同一オリジンポリシーにより、JavaScript が別オリジンのレスポンスを読むことを止めます。他サイトの JS があなたのログイン状態で API を読めたら困るからです。CORS は、サーバーが「このオリジンからなら読んでよい」とヘッダーで許可する仕組みです。

単純なリクエストとプリフライト

  • 単純なリクエスト:GET・HEAD・POST で、Content-Type が application/x-www-form-urlencoded・multipart/form-data・text/plain のどれか、独自ヘッダーなし。ブラウザはそのまま送り、レスポンスの Access-Control-Allow-Origin を見て JS に渡すか決めます。
  • プリフライト:それ以外(application/json の POST、Authorization ヘッダー付き、PUT・DELETE など)。本番の前に OPTIONS で「送ってよいか」を聞きます。
ブラウザが「読ませてよいか」をサーバーに確かめるページの JSブラウザAPI サーバーfetch(POST・JSON)単純なリクエストではない → プリフライトOPTIONS Origin: https://app.example.com204 Allow-Origin・Allow-Methods・Allow-Headers許可を確かめる → OKPOST /api/orders(本番)201 Access-Control-Allow-Originレスポンスを JS に渡す500 でヘッダーがないと「CORS エラー」に見える
プリフライトがあるときの CORS の流れ
OPTIONS /api/orders
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization

204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: content-type, authorization
Access-Control-Max-Age: 600

Cookie を送る場合は、クライアント側で credentials: 'include'、サーバー側で Access-Control-Allow-Credentials: true が要り、Allow-Origin に * は使えません。許可するオリジンは一覧で決め打ちにし、届いた Origin をそのまま返す書き方はしません。

SRE の「CORSとオリジン」

面接ではこう答える

ブラウザには同一オリジンポリシーがあり、スキーム・ホスト・ポートが違うオリジンのレスポンスを JS が読むことを止めます。CORS は、サーバーが Access-Control-Allow-Origin などのヘッダーで、このオリジンなら読んでよいと許可する仕組みです。JSON の POST や Authorization ヘッダー付きのリクエストは、先に OPTIONS でプリフライトが送られます。CORS はブラウザの仕組みなので、API を守る仕組みではない点に注意します。

別のページで開く →

ネットワーク図を読み込んでいます…

CORS(オリジン間リソース共有)は、ある画面(例:https://app.example.com)の JavaScript が、別のオリジン(スキーム・ホスト・ポートの組。例:https://api.example.com)の API を呼ぶとき、ブラウザが「サーバーが許可しているか」を確かめる仕組みです。

画面と API のドメインが分かれている構成では、開発中にも本番の障害でも CORS エラーに出会います。エラーの文言だけを見て設定を変えて回ると、本当の原因を見落とします。ここでは、調べる順番を決めておきます。

コンソールではなく Network タブから見るNetwork タブ本番と OPTIONSステータス500 なら別の原因応答ヘッダーAllow-Origin などcurl で再現Origin を付けて
CORS エラーを調べる順番

ブラウザのコンソールに CORS エラーと出ても、原因が CORS 設定とは限りません。サーバーが 500 や 502 を返したとき、そのエラー応答には CORS ヘッダーが付いていないことが多く、ブラウザは「許可がない」と表示します。本当の原因が隠れるのです。

Network タブで見えるもの疑うこと
本番のリクエストが 500・502サーバーのエラー。ログで例外を探す(CORS の設定ではない)
OPTIONS が 401・403プリフライトに認証を求めている。OPTIONS は認証なしで通す
OPTIONS が 404・405OPTIONS を受けるルートがない。CORS のミドルウェアの順番
200 なのに CORS エラーAllow-Origin にオリジンがない・違う。Allow-Headers にヘッダーが足りない
Cookie 付きのときだけ失敗Allow-Credentials: true がない、Allow-Origin: * になっている

サーバーの応答は curl -i -X OPTIONS -H 'Origin: https://app.example.com' -H 'Access-Control-Request-Method: POST' … で直接確かめられます。

CORS はブラウザの仕組みなので、curl やサーバー同士の通信には関係ありません。API を守る仕組みではない点にも注意します。

下の「ブラウザで試す」の図では、画面の読み込み → プリフライト(OPTIONS)→ サーバーが許可を返す → 本番のリクエスト → レスポンスにも許可ヘッダー、の順に進みます。上の表の「OPTIONS が 401・403」はプリフライトの段階、「200 なのに CORS エラー」はレスポンスの許可ヘッダーの段階で起きている、と対応させて見てください。後者ではサーバーは処理を終えているので、注文などがもう作られていることがある点にも注目します。

別のページで開く →

ネットワーク図を読み込んでいます…

ひとことで

HTML と CSS から DOM・CSSOM を作り、レイアウト・ペイント・合成の順で画面に描く。

ブラウザは HTML を受け取ってから、次の順で画面を作ります。この最初に表示するまでの道のりをクリティカルレンダリングパスと呼びます。

HTML と CSS から画面ができるまで同期の script と CSS の読み込みは、ここで描画を止めるHTMLDOMCSSCSSOMスタイルの決定レイアウト位置と大きさペイント合成リフロー:幅・位置が変わるとここからやり直し(重い)リペイント:色だけならここからtransform・opacity は合成だけ(軽い)
クリティカルレンダリングパスと、やり直しの範囲
  • HTML を読んで DOM(要素の木)を作る。
  • CSS を読んで CSSOM(スタイルの木)を作る。
  • 2つを合わせて、表示する要素とスタイルを決める。
  • レイアウト:それぞれの位置と大きさを計算する。
  • ペイント:色や文字を描き、重ね合わせて(合成)画面に出す。

CSS は読み終わるまで描画を止めるので、最初の表示に必要な CSS は小さくします。

リフローとリペイント

  • リフロー(レイアウトのやり直し):幅・高さ・位置が変わると起きる。周りの要素も計算し直すので重い。
  • リペイント:色など見た目だけが変わると起きる。リフローより軽い。
  • transform と opacity のアニメーションは合成の段階だけで済むので軽い。top・width を動かすより滑らかです。
  • JS で「書く→読む」を繰り返す(style を変えた直後に offsetHeight を読む、をループする)と、毎回リフローが起きます。読むのをまとめてから書きます。

JavaScript が描画を止める理由

JS は DOM を書き換えられるので、ブラウザは普通の <script> を見つけると HTML の解析を止め、ダウンロードと実行を待ちます。

書き方動き
<script src>解析を止めて取得・実行
defer並行して取得し、HTML の解析が終わってから順番に実行。普通はこれ
async並行して取得し、届いた順にすぐ実行。順番に依存しない計測タグなど向け
type="module"既定で defer と同じ動き

面接ではこう答える

ブラウザは HTML から DOM を、CSS から CSSOM を作り、合わせてレイアウトで位置と大きさを計算し、ペイントと合成で画面に描きます。CSS は読み終わるまで描画を止め、普通の script は HTML の解析を止めるので、最初に要るものを小さくし、script には defer を付けます。幅や位置を変えるとレイアウトのやり直しが起きて重いので、アニメーションは transform と opacity で行います。

ひとことで

DNS で IP を引き、TCP と TLS で安全な接続を張り、HTTP で取りに行き、ブラウザが描画する、という一連の流れ。

名前を引き、つなぎ、取りに行き、描くDNSIP アドレスを引くTCP接続を張るTLS鍵を決めて暗号化HTTPリクエストと応答描画DOM と描画HTTP/3 では TCP と TLS の代わりに QUIC が1回の往復でまとめて行う
URL を入力してから画面が出るまでの5つの段階

面接の定番の質問です。段階を順番に挙げ、それぞれで「何が起きて、どこで遅くなりうるか」を一言ずつ添えると、理解の深さが伝わります。

段階起きること遅くなる・失敗する例
DNSブラウザ・OS のキャッシュ → リゾルバーに問い合わせて IP アドレスを得るTTL が切れて毎回問い合わせる、設定ミスで引けない
TCPサーバーと3回やりとりして接続を張る(1往復)遠いサーバーほど往復が長い
TLS証明書を確かめ、暗号の鍵を決める(TLS 1.3 は1往復)証明書の期限切れ・中間証明書の不足
HTTPリクエストを送り、サーバーが処理して応答を返す。CDN にあればそこで返るサーバーの処理(TTFB)が遅い、リダイレクトが多い
描画HTML を解析し、CSS・JS・画像を取りに行って画面を作る描画を止める CSS・JS、大きな画像

2回目以降は、DNS のキャッシュ・接続の使い回し(keep-alive)・HTTP キャッシュが効くので、ずっと速くなります。

SRE の「URL入力から表示まで(話す順番)」

面接ではこう答える

まず DNS でドメイン名から IP アドレスを引きます。次に TCP で接続を張り、HTTPS なら TLS で証明書を確かめて暗号の鍵を決めます。そのうえで HTTP のリクエストを送り、サーバーや CDN が HTML を返します。ブラウザは HTML を解析して DOM を作り、CSS や JS を取りに行ってレイアウトとペイントで画面に出します。どの段階でも遅くなりうるので、性能の調査ではどこに時間がかかっているかを分けて見ます。

この章のまとめ

🖨 まとめシート(印刷・PDF)
  • URL を入力してから表示されるまでを、DNS・TCP・TLS・HTTP・描画の順に説明できる
  • キャッシュ・Cookie・CORS が「なぜそう動くか」を説明できる
  • HTTP の基本(リクエストとレスポンスの形):リクエスト(メソッド・URL・ヘッダー・本文)とレスポンス(ステータス・ヘッダー・本文)の決まった形のやりとり。
  • メソッドと冪等性:安全=サーバーの状態を変えない、冪等=何回送っても結果が同じ。GET は両方、PUT・DELETE は冪等、POST はどちらでもない。
  • ステータスコードの使い分け:4xx はクライアントが直す、5xx はサーバーが直す。正しいコードを返すと、監視・リトライ・キャッシュが正しく動く。
  • HTTP/1.1・HTTP/2・HTTP/3:1本の接続で並行に送る(多重化)のが HTTP/2、パケット消失に強い UDP 上の QUIC を使うのが HTTP/3。
  • HTTP キャッシュ:Cache-Control と ETag で、ブラウザ・CDN がレスポンスを再利用する仕組み。
  • ETag と 304・ハッシュ付きファイル名:ETag で「変わっていないか」だけを確かめて 304 で本文を省き、中身が変わるとファイル名も変わるハッシュで長期キャッシュする。
  • Cookie とセッション:サーバーが渡した値をブラウザが自動で送り返す仕組み。属性(HttpOnly・Secure・SameSite)が安全性を決める。
  • 同一オリジンポリシーと CORS:別オリジンへの読み取りはブラウザが止める。サーバーが許可ヘッダーを返したときだけ読める。
  • ブラウザの描画の流れ:HTML と CSS から DOM・CSSOM を作り、レイアウト・ペイント・合成の順で画面に描く。
  • URL を入力してから表示されるまで:DNS で IP を引き、TCP と TLS で安全な接続を張り、HTTP で取りに行き、ブラウザが描画する、という一連の流れ。

この章のクイズ

面接ではこう聞かれる

まず答えを見ずに声に出して答え、そのあと開いて比べる。

Q1URL を入力してから画面が表示されるまでを説明してください。

模範回答

まずブラウザが URL のホスト名を DNS で IP アドレスに変えます(キャッシュがあれば省略)。次にそのサーバーと TCP 接続を作り、HTTPS なら TLS のハンドシェイクで暗号化の鍵を決めます。ここまでで数往復かかるので、距離が遠いと時間がかかります。HTTP/3 なら QUIC で接続と暗号化をまとめて短くできます。

そのあと HTTP リクエストを送り、サーバー側では CDN・ロードバランサー・アプリ・DB を通ってレスポンスが作られます。サーバーの処理時間は TTFB として見えます。ブラウザは HTML から DOM、CSS から CSSOM を作り、レイアウトとペイントで画面に出します。途中で CSS や同期の script があると描画が止まるので、defer や CSS の削減で速くします。遅いときは開発者ツールのウォーターフォールで、DNS・接続・TTFB・ダウンロード・描画のどこが長いかを見ます。

深掘りされたら

  • TTFB が遅いとき、何を疑いますか?
  • CDN はどの段階を速くしますか?

見られているポイントDNS・TCP・TLS・HTTP・描画を順に、どこで時間がかかるかまで話せるか

Q2Cookie の SameSite 属性について説明してください。

模範回答

SameSite は、他のサイトから来たリクエストに Cookie を付けるかを決める属性です。Strict は他サイトからは一切付けず、Lax はリンクでの移動のような GET の画面遷移だけ付け、None はいつでも付けます(Secure が必須)。Chrome などは指定がないと Lax として扱いますが、ブラウザによって違うので明示して付けます。

CSRF は、罠サイトからユーザーのログイン Cookie 付きでリクエストを送らせる攻撃なので、Lax 以上にすると他サイトからの POST に Cookie が付かず、多くを防げます。ただし GET で更新する作りや、同じサイト扱いになるサブドメインからの攻撃は防げないので、更新は POST にしたうえで CSRF トークンや Origin ヘッダーの確認も組み合わせます。

深掘りされたら

  • SameSite=None が必要になるのはどんなときですか?

見られているポイントCSRF 対策との関係

Q3CORS エラーが出たとき、何を確認しますか?

模範回答

まず開発者ツールの Network タブで、OPTIONS のプリフライトと本番のリクエストそれぞれのステータスとヘッダーを見ます。よくあるのは、サーバーが 500 や 502 を返していて、そのエラー応答に CORS ヘッダーが付いていないために CORS エラーと表示されている場合です。その場合はサーバーのログで例外を探します。

サーバーが正常なら、Access-Control-Allow-Origin に自分のオリジンが入っているか、プリフライトに対して Allow-Methods と Allow-Headers が足りているか、Cookie を送るなら Allow-Credentials が true で Origin が * になっていないかを確かめます。OPTIONS に認証を要求していて 401 になっていることもあります。curl で Origin を付けてサーバーの応答を直接確かめると切り分けが速いです。

深掘りされたら

  • 開発中だけ CORS を避ける方法はありますか?

見られているポイントプリフライト・許可ヘッダー・実はサーバーエラー、の切り分け

Q4PUT と PATCH の違い、POST との違いは何ですか?

模範回答

PUT はリソースを丸ごと置き換える操作で、同じリクエストを何回送っても結果が同じ、つまり冪等です。PATCH は一部だけを更新する操作で、「名前を変える」なら冪等ですが、「数を1増やす」のような書き方だと冪等になりません。POST は新しく作る・処理を実行する操作で、送るたびに新しいものができるので冪等ではありません。

この違いはリトライの判断に効きます。PUT や DELETE はタイムアウトしてもそのまま送り直せますが、POST は二重に作られるので、冪等キーを付けるなどの工夫が要ります。

深掘りされたら

  • DELETE を2回送ったとき、2回目は何を返しますか?

見られているポイント冪等性とリトライへの影響

Q5ブラウザのキャッシュのせいで、デプロイ後も古い画面が出ると言われました。どう直しますか?

模範回答

まず何が古いのかを確かめます。開発者ツールの Network タブで、HTML・JS・CSS それぞれのレスポンスの Cache-Control と、ディスクキャッシュから来ているか、CDN のキャッシュヒットかを見ます。

よくある原因は、入口の HTML が長くキャッシュされていて、古い JS のファイル名を参照し続けていることです。直し方は、JS・CSS はファイル名に中身のハッシュを付けて max-age=31536000, immutable にし、HTML は no-cache にして毎回確かめさせる、という分け方です。CDN に残っている分はデプロイ時にパージします。Service Worker を使っているなら、その更新の仕組みも疑います。

深掘りされたら

  • no-cache と no-store の違いは?

見られているポイントHTML と静的ファイルの分け方、ハッシュ付きファイル名