firebase functionsはregionを間違えてもCORSになる


発生したエラー

Access to fetch at 'https://us-central1-twohundred-dcb3e.cloudfunctions.net/createMeetings' from origin 'https://twohundred-dcb3e.web.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
POST https://us-central1-twohundred-dcb3e.cloudfunctions.net/createMeetings net::ERR_FAILED
Error: internal
    at new e (3b338370d3d4d0f079e3.js:2)
    at 3b338370d3d4d0f079e3.js:2
    at t.<anonymous> (3b338370d3d4d0f079e3.js:2)
    at 3b338370d3d4d0f079e3.js:2
    at Object.next (3b338370d3d4d0f079e3.js:2)
    at c (3b338370d3d4d0f079e3.js:2)

やったこと

Nuxt+Vueでwebアプリを作るとき、firebase functionsをAPIとして利用した。

API

functions/index.js

exports.createMeetings = functions
  .region('asia-northeast1')
  .https.onCall(async (data, context) => {
    // 省略
    } catch (e) {
      console.error(new Error(e));
      return new functions.https.HttpsError('internal', e.message);
    }
  });

クライアント

store/index.js

async ADD_MEETING_URL({ commit }, { lunch }) {
    const store = firebase.firestore();
    // 正しくない
    // const functions = firebase.functions();
    // 正しい
    const functions = firebase.app().functions('asia-northeast1');
    const response = await functions.httpsCallable('createMeetings')(body);    
    await store
      .collection('Lunches')
      .doc(lunch.id)
      .set(
        {
          startURL,
          joinURL
        },
        { merge: true }
      );
  },

エラー原因

  • API側ではregionをnortheastに設定した
  • にもかかわらずクライアント側でfunctionsのregionを指定してなかった
  • デフォルトのus-centralにアクセスされてしまいCORSになった

公式ドキュメントにちゃんと注意書きされてた。。。
https://firebase.google.com/docs/functions/locations?hl=ja

勘違いポイント

「functions cors」とぐぐるとこういう記事が出てくる
https://qiita.com/qrusadorz/items/40234ac0b5c5c2315cad

FirebaseのCloud Functionsには2つの関数があります。
1. functions.https.onCall
2. functions.https.onRequest
1はSDKが用意されているAndroid,iOS,Javascriptから呼び出されるタイプ。
https://firebase.google.com/docs/functions/callable?hl=ja
2はSDKがない場合、汎用のWebAPIとして作成するタイプ。
https://firebase.google.com/docs/functions/http-events?hl=ja
タイトルのCORSが~といわれるのは2のタイプで作成していて、レスポンスにCORSのためのヘッダーが設定されていないため。
1を利用した場合、その辺の面倒な部分は内部で処理して利用者が意識しなくていいようです。

あれ、でも自分はonCallを使ってるからCORSにはならないはず、、?

そうか、開発環境でlocalhostからアクセスしてるからか!と思いきや

if (process.env.NODE_ENV === 'development') {
      functions.useFunctionsEmulator('http://localhost:5001');
    }

API側を上記のように修正してもエラーに変化なし。onCallは優秀だからlocalhostでもCORSにはならないはず

結局regionの違いに気づいたのはコンソールを見てた時

あれ、northeastに設定したはずなのにエラーはus-centralになってる、、?