JavaScript | Web API:通信・ネットワーク系 - Headers

JavaScript JavaScript
スポンサーリンク

ヘッダーは「一緒にくっついて飛んでいくメモ書き」

まずイメージからいきます。
HTTP の世界では、リクエストやレスポンスは「封筒付きの手紙」みたいなものです。

本文(ボディ)
実際の中身。JSON や HTML、テキストなど。

ヘッダー(Headers)
「これはこういう形式ですよ」「こういう条件でお願いします」といったメモ書き。

この「メモ書き」の部分を、JavaScript から扱うための仕組みが Headers オブジェクト です。
fetch で通信するとき、ほぼ必ずヘッダーを意識することになります。


Headers オブジェクトって何者か

「キーと値のセット」を扱うための専用クラス

Headers は、ざっくり言うと「文字列のキーと値のセット」を扱うためのオブジェクトです。

例えば、こんな情報を持ちます。

Content-Type: application/json
Authorization: Bearer xxx
Accept: application/json

JavaScript からは、Headers クラスとして扱えます。

const headers = new Headers();
headers.set("Content-Type", "application/json");
headers.set("X-Custom-Header", "hello");
JavaScript

でも、ふだんは fetch のオプションで素直にオブジェクトを書くだけで十分です。

fetch("/api", {
  headers: {
    "Content-Type": "application/json",
    "X-Custom-Header": "hello",
  },
});
JavaScript

このオブジェクトは内部で Headers に変換されます。
「Headers というクラスがある」と知っておけば、まずは OK です。

大事なのは「何を書くか」であって「どう書くか」ではない

初心者のうちは、new Headers() を直接触るよりも、

どんなヘッダーを付けるべきか
そのヘッダーは何を意味しているのか

を理解するほうが圧倒的に重要です。

なので、このあと「よく使うヘッダー」と「それが何を伝えているか」にフォーカスして話します。


Content-Type は「この中身は何形式か」を伝える

JSON を送るときの定番ヘッダー

一番よく見るのがこれです。

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

これは、

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

とサーバーに教えるためのヘッダーです。

例えば、ユーザー情報を JSON で送るとします。

const user = { name: "taro", age: 20 };

await fetch("/api/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify(user),
});
JavaScript

ここでやっていることは、

ボディを JSON 文字列にする(JSON.stringify
その形式を Content-Type: application/json で宣言する

というセットです。

サーバー側はこのヘッダーを見て、
「じゃあ JSON としてパースしよう」と判断します。

Content-Type を間違えるとどうなるか

例えば、ボディは JSON なのに Content-Type を付け忘れると、
サーバー側が「これは何の形式だ?」と迷います。

サーバーの実装によっては、

ボディを無視する
エラーにする
変な形で解釈してしまう

などの問題が起きます。

逆に、Content-Type だけ application/json にしておいて、
ボディが JSON になっていないと、
サーバー側でパースエラーになります。

つまり、

「ボディの中身」と「Content-Type」は必ずセットで考える

これがとても大事なポイントです。


Accept は「こういう形式で返してほしい」を伝える

クライアント側の希望を伝えるヘッダー

Accept ヘッダーは、
「レスポンスはこういう形式で返してくれると嬉しいです」という希望をサーバーに伝えます。

例えば、JSON が欲しいときはこう書きます。

await fetch("/api/user", {
  headers: {
    Accept: "application/json",
  },
});
JavaScript

サーバー側はこれを見て、
「じゃあ JSON で返そう」と判断することが多いです。

もちろん、サーバーがそれに対応していない場合もありますが、
「クライアントの希望を伝える」という意味で重要なヘッダーです。

Content-Type と Accept の違い

ここを混同しがちなので、整理しておきます。

Content-Type
「送る側のボディの形式」
リクエストなら「このリクエストボディは JSON です」
レスポンスなら「このレスポンスボディは HTML です」など

Accept
「受け取りたいレスポンスの形式」
「JSON で返してくれると嬉しいです」など

つまり、

送るときの形式 → Content-Type
欲しい返事の形式 → Accept

という役割分担です。


Authorization は「誰なのか」を伝える

認証・認可に関わる重要ヘッダー

API を叩くときによく出てくるのが Authorization ヘッダーです。

例えば、トークンベースの認証ではこうなります。

await fetch("/api/me", {
  headers: {
    Authorization: "Bearer YOUR_ACCESS_TOKEN",
  },
});
JavaScript

これは、

「このリクエストは、このトークンを持っているユーザーとして送っています」

とサーバーに伝えるためのヘッダーです。

サーバー側はこのトークンを検証して、
「このユーザーは誰か」「何が許可されているか」を判断します。

セキュリティ的な注意点もセットで意識する

Authorization ヘッダーに載せるトークンは、
盗まれたらそのままなりすましに使われる可能性がある ものです。

なので、

どこに保存するか(localStorage に長期保存しない、など)
どのタイミングで付けるか
HTTPS で送っているか

といったセキュリティの観点も非常に重要になります。

ここは「Headers の書き方」だけでなく、
アプリ全体の設計の話になってきます。


Headers オブジェクトをコードで触ってみる

リクエストにヘッダーを付ける基本パターン

一番よく使うのは、fetch のオプションでオブジェクトとして指定する形です。

await fetch("/api/data", {
  method: "GET",
  headers: {
    "X-Requested-With": "fetch-demo",
  },
});
JavaScript

このとき、内部では Headers オブジェクトに変換されています。

もう少し直接的に書くこともできます。

const headers = new Headers();
headers.set("X-Requested-With", "fetch-demo");
headers.set("Accept", "application/json");

await fetch("/api/data", { headers });
JavaScript

レスポンスのヘッダーを読む

Response 側のヘッダーも、headers プロパティから読めます。

const response = await fetch("/api/data");

console.log(response.headers.get("Content-Type"));
console.log(response.headers.get("X-RateLimit-Remaining"));
JavaScript

例えば、

Content-Type で「返ってきたデータの形式」を確認する
X-RateLimit-Remaining で「あと何回リクエストできるか」を知る

といった使い方ができます。

ヘッダーは「メタ情報(付帯情報)」なので、
ボディとは別に「どう扱うか」を考える必要があります。


具体例:JSON API を叩くときのヘッダー設計

よくあるパターンを一つにまとめてみる

JSON ベースの API を叩くときの、
「いい感じのテンプレート」を作ってみます。

async function fetchJson(url, options = {}) {
  const defaultHeaders = {
    Accept: "application/json",
    "Content-Type": "application/json",
  };

  const mergedHeaders = {
    ...defaultHeaders,
    ...(options.headers || {}),
  };

  const response = await fetch(url, {
    ...options,
    headers: mergedHeaders,
  });

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

  return response.json();
}
JavaScript

ここでやっていることは、

JSON を送る・受け取る前提で
AcceptContent-Type をデフォルトで付ける
呼び出し側が追加でヘッダーを指定できるようにマージする

という設計です。

使う側はこう書けます。

const user = await fetchJson("/api/user/1");

const created = await fetchJson("/api/users", {
  method: "POST",
  body: JSON.stringify({ name: "taro" }),
});
JavaScript

毎回ヘッダーを手書きするのではなく、
「自分のアプリの標準ヘッダー」を一箇所にまとめておくと、
ミスも減るし、読みやすさも上がります。


初心者としてヘッダーで本当に意識してほしいこと

最後に、あなたの頭の中に残しておいてほしいポイントを整理します。

ヘッダーは「本文とは別にくっついて飛んでいくメモ書き」
Content-Type は「このボディは何形式か」を伝える(送る側の宣言)
Accept は「こういう形式で返してほしい」を伝える(受け取り側の希望)
Authorization は「誰としてアクセスしているか」を伝える(セキュリティの要)
ヘッダーは Request と Response の両方にあり、会話のルールや形式を決めている
ボディの中身と Content-Type は必ずセットで考える

おすすめの練習は、
自分が書いた fetch のコードを見直して、

このリクエストの Content-Type は何になっているべきか
Accept を付けるなら何を指定するか
レスポンスの Content-Type を見て、json()text() をどう使い分けるか

を一つずつ言語化してみることです。

ヘッダーを「よく分からないおまじない」から、
「サーバーとの会話のルールを決める大事なメモ」 として扱えるようになったとき、
あなたのネットワーク周りのコードは一気に説得力を持ち始めます。

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