ふぁっ、ふぁっ、ふぁーーんっくしょん!
この記事は sadnessOjisan Advent Calendar 2021 10 日目の記事です。 書かれた日付は 12/18 です。 8 日サボったのはさすがにやりすぎた。
今日は onCall についてです。 onCall を使ったときに CORS で怒られることがある。
Access to fetch at 'https://asia-northeast1-nensyu-match-development.cloudfunctions.net/hoge' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
onCall とは
Firebase Functions, Cloud Functions は文字通り Function 単位でデプロイできる、FaaS である。そのため基本的には HTTP 経由で関数を実行する。しかしこれらには JS 用の SDK が用意されていて、HTTP を使わずにライブラリ経由で関数を実行できる。
const functions = getFunctions(app, "asia-northeast1");
export const addUserData = httpsCallable(functions, "xxx");
addUserData({ name: "yosuke", age: 17 });
なにが嬉しいか
この記法を使うことによる嬉しさは、自分でしないといけない手癖をもろもろやってくれることだ。例えば、認証や CORS があげられる。
認証を例に挙げると、これまではクライアント側で idToken の生成と header の追加をして、その token の decode として Function 側で
const match = req.headers.authorization?.match(/^Bearer (.*)$/);
if (match === undefined || match === null) {
throw new Error("authed err");
}
const idToken = match[1];
admin.auth().verifyIdToken(idToken);
のような処理を書く必要があったが、それが onCall があれば
context.auth.uid;
だけで済む。
このように便利だが、なぜが CORS エラーがよく発生する。その理由や対策について。
CORS のエラーじゃなくても CORS のエラーが出ているだけ
CORS が原因で出ているのではなさそうです。存在しない関数を呼ぶとそのようなエラーが出ているようです。
存在しない関数名
export const route = functions
.region("asia-northeast1") // TODO: 関数の先頭は共通化できそう
.https.onCall(async (data, context) => {
}
として定義したのに、
const functions = getFunctions(app, "asia-northeast1");
export const root = httpsCallable(functions, "xxx");
root({ name: "yosuke", age: 17 });
と route と root でタイポすると、
Access to fetch at 'https://asia-northeast1-nensyu-match-development.cloudfunctions.net/hoge' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
のようなエラーが発生。
Region
onCall ではデプロイするリージョンを指定できますが、その指定先と実際のリクエストの region が異なると CORS のエラーが発生。
const functions = getFunctions(app); // 指定しないとデフォルトリージョンがセットされアメリカにリクエストが飛ぶ
export const root = httpsCallable(functions, "xxx");
root({ name: "yosuke", age: 17 });
まとめ
落ち着いて、ゆっくり。