Zenn

GASのおかげでwebエンジニアに近づいた

2025/03/11に公開

はじめに

こんにちは。スペースマーケットでWebエンジニアしてます、新卒のdumbled0reです。

今回は初めてGASに触った時に発生したエラーのおかげでWebエンジニアに近づいたお話しです。

こんなエラーが発生した

Access to fetch at 'https://script.google.com/macros/s/[デプロイURL]/exec' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

JavaScriptのコード

fetch("https://script.google.com/macros/s/[デプロイURL]/exec", {
  method: "POST",
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "佐藤太郎"
  }),
})

Access to fetch at 'https://script.google.com/macros/s/[デプロイURL]/exec' from origin 'null' has been blocked by CORS policy

オリジン 'null' からの 'https://script.google.com/macros/s/[デプロイURL]/exec' へのアクセスは、CORSポリシーによってブロックされましたと言われたけど、オリジンとかCORSポリシーってなんやねん、、
※ローカルファイルをブラウザに表示しただけなので、オリジンがnullになっています。

オリジンとは

オリジンとは 「プロトコル」「ドメイン」「ポート番号」 の3つの組み合わせで決まります。
例えばhttp://example.com/app/index.htmlのようなURLが存在した場合、プロトコルはhttp、ドメインはexample.com、ポートはhttpのデフォルト値である80(デフォルトの場合は省略可能)なので、オリジンはhttp://example.comになります。

今回の場合、ブラウザ側はオリジンがnullでGAS側はオリジンがhttps://script.google.comになるので、異なるオリジンになるということか。

CORSとは

CORSとは「Cross-Origin Resource Sharing」の略で、ブラウザが異なるオリジンに対してリクエストを送る際のセキュリティチェックを行い、リクエストが許可されているか確認する仕組みのことです。ブラウザは他のオリジンからのデータ取得を制限しています。

つまり、GAS側でnullというオリジンを許可すればアクセスできるようになるということか。
GAS側でAccess-Control-Allow-Origin*にしてもなかなかエラーが解消されない。

どうやらリクエストには2種類存在するらしい

リクエストには安全なリクエスト(Simple Request)と安全ではないリクエスト(Non-Simple Request)が存在します。

安全なリクエスト

  1. HTTPメソッドが以下のいずれか
    • GET
    • POST
    • HEAD
  2. ヘッダーが以下のいずれか
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(以下のいずれかの値のみ)
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

安全ではないリクエスト

上記の安全なリクエスト以外になります。
例えばHTTPメソッドがPUTDELETEOPTIONSContent-Typeの値がapplication/jsonなどです。

そして、この安全ではないリクエスト時には「プリフライトリクエスト」というものが走ります。
プリフライトリクエストは実際のリクエストの前にブラウザがサーバーに対して「このリクエストを送っても大丈夫?」と事前確認しています。

今回のJSのコードでもContent-Typeapplication/jsonに設定していたので、プリフライトリクエストが走っています。GASはOPTIONSを受付られない仕様になってるそうなので、本来ならAccess-Control-Allow-Originを適切に設定すればOKのはずですが、 OPTIONSで飛ぶプリフライトを受け付けないから今回は別の方式を取りました。

対処方法

プリフライトが走るとCORSエラーが発生するのが分かったので、プリフライトが走らない安全なリクエストに変更したらよい。2つ紹介します。

Content-Typeを変更する

Content-Typeapplication/jsonからapplication/x-www-form-urlencodedに変更して、Content-Typeの値にあった送信をするように修正しました。今回はapplication/x-www-form-urlencodedにしてますが、text/plainでも大丈夫です。
JavaScriptのコード

fetch("https://script.google.com/macros/s/[デプロイURL]/exec", {
  method: "POST",
  headers: {
    Accept: "application/json",
    // application/json -> application/x-www-form-urlencodedに修正
    "Content-Type": "application/x-www-form-urlencoded",
  },
  // URLエンコード
  body: new URLSearchParams({
    name: "佐藤太郎",
  }),
})

GAS側

function doPost(e) {
  const name = e.parameter.name;
}

GETメソッドをPOSTメソッド風に扱う

GETメソッドをPOSTメソッド風に扱うなんて普段の開発ではしないことですが、doGet関数を使う予定がないのであれば、手っ取り早いです。

JavaScriptのコード

fetch(`https://script.google.com/macros/s/[デプロイURL]/exec?name=${encodeURIComponent("佐藤太郎")}`, {
  method: "GET",
  headers: {
    Accept: "application/json",
  },
})

GAS側

function doGet(e) {
  const name = e.parameter.name;
}

これで無事にJSとGASで連携することが出来ました!!!

まとめ

はじめてGASに触ってみて、Webエンジニアであれば当たり前のように知っていることも少しは分かるようになり、Webエンジニアに近づけたのかと思いました!GASに感謝!!!

さいごに

スペースマーケットでは一緒にサービスを成長させていく仲間を探しています!
新卒でもフロントエンドからインフラまで幅広く関わることでき、成長できる環境があります。
ご興味ある方はこちらからご応募お待ちしております!

スペースマーケット Engineer Blog

Discussion

ログインするとコメントできます