概要
Firebase Cloud FunctionsのHTTPS呼び出し可能関数をregion指定つけた状態で,FunctionsもエミュレートするようにしたFirebase Local Emulatorからアクセスすると「CORS」エラーが発生してしまいました.本記事はその対処法を記載しています.
解決策まとめ
ブラウザの開発者ツール等からエミュレート実行中のinit.jsの内容をコピーし,Functionsの設定部を下記のように変更し,scriptから利用します.
firebase.app().functions('asia-northeast1').useEmulator(firebaseEmulators.functions.host, firebaseEmulators.functions.port);
環境
- firebase-tools 9.23.3
- クライアント側Firebaseソースバージョン 8.8.0 (v8 Web)
発生状況
Firebase Cloud Functionsではクライアント側から認証情報を乗せたまま叩ける「HTTPS呼び出し可能関数」があります.
アプリから関数を呼び出す | Firebase Documentation
次のような,EmulatorでFunctionsをテストできるソースがあるとします.
const functions = require('firebase-functions');
exports.testCall = functions.region('asia-northeast1').https.onCall(async (data, context) => {
return "ok"
})
<html>
<head>
<script src="/__/firebase/8.8.0/firebase-app.js"></script>
<script src="/__/firebase/8.8.0/firebase-auth.js"></script>
</script>
<script src="/__/firebase/init.js?useEmulator=true"></script>
</head>
(中略)
<script>
const firebaseConfig = { ... }
firebase.initializeApp(firebaseConfig)
const func = firebase.app().functions('asia-northeast1').httpsCallable("testCall")
func()
.then((r)=>{ console.log(r) })
</script>
</html>
この状態で firebase emulators:start
してlocalのtest.htmlにアクセスするとブラウザのコンソールの方に次のようなエラーが出て実行されません.
Access to fetch at 'https://asia-northeast1-xxx.cloudfunctions.net/testCall' from origin 'https://xxx.firebaseapp.com' 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.
init.js?useEmulator=true
のscriptタグが無い状態で firebase deploy すると問題なく動くのがやっかいなところです.
原因
実はログにヒントがあり,regionを指定しない場合,つまり
firebase.functions().httpsCallable("testCall")
では
https://localhost:5001/xxxxx/us-central1/testCall
にアクセスするはずですが,ログではデプロイ後のURIにアクセスしています.
同じ現象→ Firebase Functionsを呼び出す際にregion指定するとEmulatorではなく本番に接続してしまう
Emulatorを使うための init.js をブラウザで確認すると,
if (firebaseEmulators.functions && typeof firebase.functions === 'function') {
firebase.functions().useEmulator(firebaseEmulators.functions.host, firebaseEmulators.functions.port);
}
というコードでFunctionsがエミュレートで動くように設定されていますが, us-central1リージョンのfirebase.functions()
だけがエミュレーション動作設定になってしまっており, asia-northeast1リージョンの firebase.app().functions('asia-northeast1')
はエミュレート設定になっていないというのが根本原因となります.
対処法
init.js によるエミュレート設定を使う以上は回避できなさそうですので,別途エミュレート設定を記述する必要があります.
init.jsの内容をコピーし,Functionsの設定部を下記のように変更します.
firebase.app().functions('asia-northeast1').useEmulator(firebaseEmulators.functions.host, firebaseEmulators.functions.port);
これにより正常にHTTPS呼び出し可能関数を使うことができるようになりました.