Node.js の fetch で「Request with GET/HEAD method cannot have body」エラーが出る理由と対処法

Node.js 18 以降では、fetch標準API として組み込まれました。これにより、ブラウザとほぼ同等の Fetch API が Node.js でも使えるようになりましたが、その一方で次のようなエラーに遭遇するケースが増えています。

TypeError: Request with GET/HEAD method cannot have body

「今まで動いていたコードなのに、Node を上げたら突然エラーが出た」という人も多いはずです。本記事では、このエラーが発生する根本的な理由と、実務で使える回避策を整理します。

このエラーが発生する背景

Node.js 18 以降の fetch は仕様に厳密

Node.js 18 から導入された fetch は、内部的に WHATWG Fetch Standard に準拠しています。これはブラウザの fetch と同じ仕様であり、HTTP のルールを厳密に守ります。

その結果、以下の制約がそのまま適用されます。

  • GET / HEAD メソッドでは body を持てない
  • body を指定した時点で例外を投げる

これは Node 独自の制限ではなく、HTTP仕様上の正当な挙動です。

過去のライブラリでは黙認されていた

以前よく使われていた以下のようなライブラリでは、GET + body が暗黙的に許容されていました。

  • node-fetch(古いバージョン)
  • request
  • axios(一部の設定)

そのため「GET で body を送る」というアンチパターンが、実務コードに残っていることが少なくありません。

よくあるエラー例

GET に body を指定している

以下のコードは Node.js 18 以降ではエラーになります。

await fetch('https://api.example.com/users', {
  method: 'GET',
  body: JSON.stringify({ id: 1 }),
})

ブラウザでも同様に、この書き方は仕様違反です。

なぜ GET で body を送れないのか

HTTP仕様上の理由

HTTP/1.1 および Fetch Standard では、GET リクエストは次の性質を持ちます。

  • リソースの取得が目的
  • 副作用を持たない
  • キャッシュ可能
  • URL(クエリ)によって完全に表現される

このため、body を許可すると以下の問題が発生します。

  • キャッシュのキーに含まれない
  • プロキシやCDNが無視する
  • サーバー・クライアント間で挙動が不一致になる

これを防ぐため、Fetch API では 明示的に禁止されています。

実務での回避策

1. クエリパラメータに変換する(最優先)

最も正しい解決方法

GET を使いたい場合は、body ではなく URL クエリに変換します。

const params = new URLSearchParams({ id: '1' })

await fetch(`https://api.example.com/users?${params}`)

向いているケース

  • 検索条件
  • ID指定
  • フィルタ条件
  • キャッシュさせたいAPI

2. POST に切り替える

データを送るなら POST が正解

body を送りたい場合は、HTTPメソッド自体を見直します。

await fetch('https://api.example.com/users/search', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ id: 1 }),
})

判断基準

  • データ量が多い
  • 検索条件が複雑
  • キャッシュ不要

この場合、エンドポイント設計を分けるのがベストプラクティスです。

3. HEAD メソッドでも同様に注意

HEAD も body は送れない

HEAD は GET と同様に body を持てません。

await fetch(url, {
  method: 'HEAD',
  body: 'xxx', // 同じエラーになる
})

レスポンスヘッダだけが欲しい用途に限定して使いましょう。

Node.js fetch 特有の注意点

axios からの移行時にハマりやすい

axios では次のような書き方が可能でした。

axios.get('/api', { data: { id: 1 } })

これをそのまま fetch に置き換えるとエラーになります。

fetch 移行時のチェックポイント

  • GET/HEAD に body を渡していないか
  • 検索APIが POST の方が適切ではないか
  • クエリ化できる設計になっているか

エラーを回避するための設計指針

API設計側で意識すべきポイント

  • GET: クエリのみ、キャッシュ前提
  • POST: body を使った検索・処理
  • PUT/PATCH: 更新
  • DELETE: 削除

Node.js の fetch は「仕様に厳しい」だけで、間違った設計を教えてくれる存在とも言えます。

まとめ

Node.js の fetch で発生する
「Request with GET/HEAD method cannot have body」エラーは、バグではありません。

ポイント整理

  • Node.js 18 以降の fetch は仕様準拠
  • GET / HEAD に body は送れない
  • クエリ or POST に設計を切り替えるのが正解
  • 古いコード・axios 移行時は特に注意

このエラーに遭遇したら、「回避する」のではなく API設計を見直すサイン として捉えるのが、長期的には最も安全です。

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