FirebaseのCloud FunctionsでHttps.onRequestのCORS問題を回避
静的サイトの問い合わせフォームをCloud Functionsで作ろうとしてハマる
みなさん静的サイトは作っていますか?脱Wordpressを掲げて第一弾としてNipoPlusの姉妹アプリであるMaroudのホームページを静的サイトに作り変えました。 静的サイトとはHTMLが生成された状態でサーバに置いておくだけのWebサイトです。WordpressなどはPHPでアクセスの度ページを作成するので「動的サイト」と呼ばれます。
静的サイトのメリットとして
- セキュリティに強い(サーバにプログラムが無いため)
- 高速(サーバでの処理がなく、HTMLを返すだけだから)
- SEO対策もできる(HTMLなので)
といった点がありますが、実は無視できない大きなデメリットが1つあります。それが **「問い合わせフォームでメール送信ができない」**という問題です。 サーバ側でメールを処理するプログラムが置けないので、問い合わせフォームに関しては別途用意しなければなりません。 今回はMaroudのWebサイトを静的サイトに切り替えたとき、問い合わせフォームの設置に思いの外苦労したことをお話します
ホスティング先がFirebaseなので問い合わせフォームはCloud Functionsで実装したい
MaroudはアプリもWebページもFirebase上にホスティングされています。なので問い合わせフォームの処理自体もFirebase上に実装するのが一番しっくりきます。 Firebaseのホスティングではサーバ側のプログラムを設置できないため、FirebaseのCloud Functionsを使うことになります。 ホームページからの問い合わせフォームなのでアカウントが無いユーザでも気軽に問い合わせができる状態にする必要があります。 少し調べたところ、
という書き方が可能なことを突き止めました。詳しくはこちら。 これでかんたんにHttpのリクエストを受けてプログラムを走らせることができます。 簡易的な問い合わせフォームには十分でしょう。メール送信などのプログラムについてはここでは触れません。
フロントエンドではAxiosを使ってhttpリクエストを送るように作る。ここでCORS発生
フロント側では問い合わせフォームに入力された内容を元に、httpリクエストを発行します。Axiosを使って実装しました。
こんな感じですね。
はい、ここで悪名高きCORSのエラーが帰ってきます
公式サイトによれば、「Express使えばええやん。ExpressのCORSミドルウェアええで」と言わんばかりのマニュアルです。 しかしWebサイトの問い合わせフォームだけのためにExpressやらCORSをインストールしたく有りません。 Cloud Functionsはできるだけシンプルに保ちたいと思い、なにか方法が無いか調べたところ、Cloud Functionsの関数の頭に
と書くことでいけるらしいではありませんか。
早速Cloud Functionsに追記してみました。
再度リクエストするとCORSエラー。うん、知ってた。 しかしCURLでアクセスするとちゃんと正しくアクセスできていることが確認できました。 ブラウザのネットワークをよく見てみると、Preflightなるアクセスを先に行っており、どうもこれが原因でまたエラーが発生しているようです。
だらだら書いても仕方ないので、結論を
とりあえず次のように書くと、CORSの問題を回避できました
CURLでは正しくアクセスできたのに、Webブラウザからリクエストすると弾かれる問題、原因はこのPreFlightであることが濃厚です。 PreFlight時に発生したエラーメッセージから、Access-Control-Allow-Headersが欠けていることがわかったのでそれを追記してあげたところ、無事に動くようになりました。
フロントエンドの開発ばかりしているので、どうにもこのサーバ周りの話は苦手ですね。サーバの管理をしなくても開発できるようなサービスとしてFirebaseは非常に優秀ですが、今回は久しぶりにハマりました。 解決までに3時間も費やしてしまいました。参考にさせていただいたサイトたち
- FirebaseのCloud FunctionsでCORSが~とかAccess-Control-Allow-Originが~と言われたらこれ
- Preflight request (プリフライトリクエスト)
- Enabling CORS in Cloud Functions for Firebase
- Cloud Functions for Firebase で CORS エラーを回避する
同じ悩みを抱えている方に少しでも役に立てればと思い記事を書きました