tech.sinayaka.com

GASへのfetchでno-corsとContent-Typeを両方書いたら動かなかった

2026-05-01
2026-06-05
3分
548語
Web技術 GASJavaScriptfetch

お問い合わせフォームの送信がGoogle Apps Script(GAS)に届かない、という問題にハマった。コードを見ると一見正しそうなのに、GASのログには何も残っていない。

問題のコード

const postparam = {
  method: "POST",
  mode: "no-cors",
  "Content-Type": "application/x-www-form-urlencoded",  // ← ここがバグ
  body: JSON.stringify(forms)
};
await fetch(url, postparam);

何がおかしかったか

"Content-Type" がトップレベルに書かれている。fetch() のオプションとしてHTTPヘッダーを指定するには headers オブジェクトの中に書く必要がある。

// ❌ 無効(fetchのオプションとして無視される)
{
  mode: "no-cors",
  "Content-Type": "application/x-www-form-urlencoded",
}

// ✅ 有効
{
  mode: "no-cors",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
}

トップレベルに書いた "Content-Type" はfetchに無視される。つまりヘッダーが送信されていなかった

no-corsとContent-Typeのもう一つの問題

さらに複雑なのが mode: "no-cors" の動作だ。

no-cors モードでは、リクエストは「シンプルリクエスト」として送られる。シンプルリクエストで許可されるContent-Typeは:

  • text/plain
  • application/x-www-form-urlencoded
  • multipart/form-data

の3つだけ。application/json は許可されない。

ところがこのコードはContent-Typeに application/x-www-form-urlencoded を指定しながら、bodyは JSON.stringify() でJSON文字列を送っている。宣言と内容が矛盾している。

結果的に動いた方法

別のサイトで同じGASに送信するコードが動いていたので中を見たら、なんとバグを含んだまま動いていた。

// Content-Typeがトップレベルにあるバグコード(でも動いている)
{
  method: "POST",
  mode: "no-cors",
  "Content-Type": "application/x-www-form-urlencoded",  // 無視される
  body: JSON.stringify(forms)
}

ヘッダーが送信されないため、ブラウザはデフォルトで text/plain;charset=UTF-8 を使う。GAS側では e.postData.contents でJSON文字列をそのまま受け取り、JSON.parse() できる。結果的に動いていた。

正解はこう:

await fetch(url, {
  method: 'POST',
  mode: 'no-cors',
  body: JSON.stringify({ name, email, message }),
  // Content-Typeは省略 → text/plainになりGASが読める
});

GAS側:

function doPost(e) {
  const data = JSON.parse(e.postData.contents);
  // data.name, data.email, data.message が使える
}

まとめ

状況結果
headers: { "Content-Type": "..." }mode: "no-cors"Content-Typeが application/x-www-form-urlencoded なら有効
トップレベルに "Content-Type"無視される → text/plain になる
mode: "no-cors" でJSONボディContent-Typeを省略して text/plain にすれば届く

GASに no-cors でJSONを送る場合は、Content-Typeを書かずに body: JSON.stringify(...) だけにするのが一番シンプルだ。




Copyright 2026
サイトマップ