JavaScript | Web API:通信・ネットワーク系 - Request / Response オブジェクト

JavaScript JavaScript
スポンサーリンク

「Request / Response」は fetch がやり取りする“手紙の入れ物”

まず大きなイメージからいきます。

fetch は「サーバーと会話する窓口」でしたよね。
その会話の中で実際に行き来しているのが、

送る側の情報をまとめた Request オブジェクト
返ってきた情報をまとめた Response オブジェクト

です。

つまり、

あなた → サーバー に送る「手紙」が Request
サーバー → あなた に返ってくる「返事」が Response

と考えると分かりやすいです。

ふだんは fetch(url, options) と書くだけで、裏側で勝手に Request が作られ、返ってきた Response を受け取っています。
でも、この二つをちゃんと意識できるようになると、通信の理解が一段深くなります。


Response オブジェクトをちゃんと理解する

Response は「サーバーからの返事のまとまり」

fetch の戻り値(Promise が解決したときの中身)は、Response オブジェクトです。

const response = await fetch("https://example.com/api/user");
JavaScript

この response の中には、サーバーからの返事に関する情報がまとまっています。

ステータスコード(200, 404, 500 など)
ヘッダー(Content-Type など)
ボディ(中身)をどう読むかのメソッド

などが入っています。

「HTTP レスポンスを JavaScript から扱いやすくしたもの」が Response だと思ってください。

ステータスコードと ok プロパティ

まずよく使うのが statusok です。

console.log(response.status); // 200, 404, 500 など
console.log(response.ok);     // 200〜299 のとき true、それ以外は false
JavaScript

ここがとても重要です。

fetch 自体は、サーバーが 404 や 500 を返しても「エラーにはしない」
「通信は成功したけど、サーバー側の結果はエラーだった」という状態を自分で判定する必要がある

そのために response.ok を見るのが定番パターンです。

if (!response.ok) {
  throw new Error(`HTTP error: ${response.status}`);
}
JavaScript

ボディを読むメソッド(json / text など)

Response の中身(ボディ)は、そのままでは使えません。
「どういう形式で読みたいか」をメソッドで指定します。

JSON として読みたいときは json()

const data = await response.json();
JavaScript

テキストとして読みたいときは text()

const text = await response.text();
JavaScript

この二つはどちらも非同期で、Promise を返します。
つまり、

await fetch(...) でレスポンスヘッダーまで取得
await response.json() でボディをパース

という「二段階で読む」イメージが大事です。

Response は一度しか“読めない”という性質

Response のボディは「ストリーム」なので、基本的に一度しか読めません。

const data1 = await response.json();
const data2 = await response.json(); // ここはエラーになる
JavaScript

一回 json()text() で読んだら、それでおしまいです。
同じ Response から何度もボディを取り出すことはできません。

もしどうしても複数の場所で使いたいなら、
一度変数に入れて、それを渡していく設計にします。

const data = await response.json();
useA(data);
useB(data);
JavaScript

Request オブジェクトは「送る内容をまとめたもの」

fetch は内部で Request を勝手に作っている

ふだんはこう書いていますよね。

fetch("https://example.com/api/user", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "taro" }),
});
JavaScript

このとき裏側では、

URL
HTTP メソッド(GET / POST など)
ヘッダー
ボディ

といった情報をまとめた Request オブジェクト が作られています。

つまり、fetch

Request を作る
その Request をサーバーに送る
返ってきた Response を Promise で返す

ということをやっているわけです。

Request を自分で作ることもできる

必要であれば、自分で new Request(...) してから fetch に渡すこともできます。

const req = new Request("https://example.com/api/user", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "taro" }),
});

const response = await fetch(req);
JavaScript

こうすると、

同じ Request を何度か使い回したい
Request を別の関数に渡したい

といったときに便利です。

ただ、初心者のうちは「fetch(url, options) で十分」と思っていて大丈夫です。
「裏側では Request が作られている」というイメージだけ持っておけば OK です。

Request からもヘッダーやメソッドを参照できる

Request オブジェクトも、いろいろな情報を持っています。

console.log(req.method); // "POST"
console.log(req.url);    // "https://example.com/api/user"
console.log(req.headers.get("Content-Type")); // "application/json"
JavaScript

Service Worker や高度な処理を書くときには、
Request を受け取って中身を見て処理を分岐する、ということもよくあります。


Request / Response をセットでイメージする

一連の流れをコードで眺めてみる

シンプルな GET の例を、Request / Response の視点で見直してみます。

async function loadUser() {
  const url = "https://example.com/api/user";

  // ここで内部的に Request が作られる
  const response = await fetch(url);

  // ここから Response を扱う
  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }

  const user = await response.json();
  console.log(user);
}
JavaScript

流れとしては、

URL から Request が組み立てられる
Request がサーバーに送られる
サーバーが Response を返す
Response のステータスやボディを見て処理を決める

という感じです。

POST の例だと、Request の中身が少しリッチになります。

async function createUser(user) {
  const response = await fetch("https://example.com/api/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(user),
  });

  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }

  const created = await response.json();
  console.log(created);
}
JavaScript

ここでは、

Request のメソッドが POST
ヘッダーに Content-Type が付く
ボディに JSON 文字列が入る

という形で、「送る側の情報」が Request にまとまっています。


ヘッダーを通して Request / Response が“会話”している

Request ヘッダーで「こういう形で送るよ」と伝える

例えば JSON を送るとき、こんなヘッダーを付けます。

headers: {
  "Content-Type": "application/json",
}
JavaScript

これは、

「このリクエストのボディは JSON ですよ」

とサーバーに伝えるための情報です。

サーバー側はそれを見て、
「じゃあ JSON としてパースしよう」と判断します。

Response ヘッダーで「こういう形で返すよ」と伝える

逆に、サーバーからの返事にもヘッダーがあります。

console.log(response.headers.get("Content-Type")); // "application/json" など
JavaScript

ここで Content-Type: application/json なら、
「このレスポンスのボディは JSON ですよ」という意味です。

だからこそ、クライアント側では response.json() を呼ぶわけです。

Request と Response は、
ヘッダーを通して「データの形式」や「追加情報」をやり取りしています。

このやり取りを意識できるようになると、
「なぜここでこのヘッダーを付けるのか」が理解しやすくなります。


初心者として本当に押さえておきたいポイント

最後に、あなたの頭の中に残しておいてほしいことを整理します。

fetch の結果は Response オブジェクト
Response にはステータス(status / ok)、ヘッダー、ボディ読み取りメソッド(json() / text())がある
ボディは一度しか読めないので、json()text() は一回だけ呼ぶ
Request は「送る内容をまとめたオブジェクト」で、fetch(url, options) で裏側で作られている
POST などでは、Request のメソッド・ヘッダー・ボディを意識して設計する
Request / Response は、ヘッダーを通して「どういうデータを送る・返すか」を会話している

おすすめの練習は、
今まで書いた fetch のコードを見直して、

「ここで作られている Request はどんな中身になっているか」
「返ってきた Response から何を見て、どう判断しているか」

を言葉にして説明してみることです。

それがスラスラ言えるようになったとき、
あなたはもう「なんとなく fetch を使っている人」ではなく、
「Request / Response の会話を設計できる人」 に近づいています。

タイトルとURLをコピーしました