フォーム内容送信時にGoogleForm専用の送信完了画面に飛ぶのが嫌
→とりあえず非同期通信(axios)で送信してみる
→CROSのエラー↓が出る
「Failed to load https://docs.google.com/forms/XXXXXX/formResponse: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.」
まず、エラーが出てても非同期通信はうまくいきます。
参考:Googleフォームをカスタマイズして導入、Ajax処理を行う
でもエラーハンドリングできないの嫌だよね。回避しよう。
そもそもなぜエラーが出るのか
ブラウザ(特にChrome)では、セキュリティ対策としてオリジン (ドメイン、プロトコル、ポート番号) の違うクライアントとサーバで通信することに制限かけているらしい。クロスドメインってやつですね。基本的にはCROSを許可する(=サーバサイドのHTTPヘッダーで特定のオリジンからのアクセスを許可する)ことでこのエラーは解決できるみたいなんだけど、どうやらGoogle FormではHTTPヘッダーの設定ができないらしい。(探しきれなかったけどもしかしたらGASでは方法があるかも。要検討)
CROS詳しくはここがよかった
オリジン間リソース共有 (CORS)
回避方法:CROSプロキシを経由して通信を行う
似たような事例の場合、自分でローカルにプロキシサーバ立てて経由するのが一般的みたいだけど、今回はサーバレス(Firebase)で開発してたので公開されてるCORSプロキシを使用してみた。セキュリティにそこまで気を使わなくてもいい個人のWebサイト程度ならこの方法でいいんじゃないかなーと思う。今回使用したのは以下のプロキシ
cors-anywhere
実際のソースはこんな感じになった。submitするurlの前にプロキシurl連結しただけ。
その他回避方法
フリーのプロキシを経由することに抵抗がある場合、「submit時の遷移先を非表示のiframeに設定することでエラーを起こさせない」という方法もある。非同期通信せずに通常通りフォームの内容をsubmitして、送信完了画面をiframeに表示するように設定し、更にそのiframeを非表示に設定することによってエラーを回避する。
formタグにtarget属性を設定することによって遷移先を新規ウィンドウorフレームに表示することができる
詳細はここで
結果が表示されるウィンドウを指定する
コードはこんな感じで
シンプル。エラーハンドリングはできないけど、とりあえずエラー回避だけするって場合はこれでもいい。
あとは未検証なんだけど、非同期通信で送信するデータの形式を「json」ではなく「jsonp」にすることでCROSエラーを回避できる場合があるらしい。
ただしaxiosではデータ形式にjsonpは設定できないので、やる場合はaxiosの公式ドキュメントで推奨されてる方法が良さそう。