Cloud Functions for FirebaseでCORSを有効にする


141

現在、Firebase向けの新しいCloud Functionsの使用方法を学んでいますが、AJAXリクエストを介して記述した関数にアクセスできないという問題があります。「 'Access-Control-Allow-Origin'がありません」というエラーが表示されます。これが私が書いた関数の例です:

exports.test = functions.https.onRequest((request, response) => {
  response.status(500).send({test: 'Testing functions'});
})

関数は次のURLにあります:https : //us-central1-fba-shipper-140ae.cloudfunctions.net/test

Firebase docsは関数内にCORSミドルウェアを追加することを提案していますが、試してみましたが、機能しません:https : //firebase.google.com/docs/functions/http-events

これは私がそれをした方法です:

var cors = require('cors');    

exports.test = functions.https.onRequest((request, response) => {
   cors(request, response, () => {
     response.status(500).send({test: 'Testing functions'});
   })
})

何が悪いのですか?これで何か助けていただければ幸いです。

更新:

Doug Stevensonの回答が役立ちました。({origin:true})を追加すると問題が修正され、最初は完全に見落としたものに変更response.status(500)する必要もありましたresponse.status(200)


また、ドキュメントのサンプルはこちら
加藤

提供されたソリューションで機能するいくつかの関数がありますが、現在、本質的に開いているグラフをindex.htmlの上部に追加し、更新されたindex.htmlを返す新しい関数を試していますが、それを機能させることができません:( ACCESS-CONTROL ---エラー
TheeBen

2
着信リクエストを上記のようにcors()でラップすることが私にとってうまくいった唯一のことでした
Charles Harring

corsミドルウェアが必要であることを強調するために「更新」を編集できますか?これにより、時間を節約できる人もいます
Antoine Weber

回答:


151

CORSの使用を示す、Firebaseチームが提供する2つのサンプル関数があります。

2番目のサンプルでは、​​現在使用している方法とは異なる方法でcorsを操作します。

また、サンプルに示すように、次のようにインポートすることを検討してください。

const cors = require('cors')({origin: true});

2
ありがとうございました!({origin:true})を追加すると役立ちました。
Andrey Pokrovskiy 2017年

2
いいですね、origin: trueこれを
Scott

4
これは、アクセスを許可するドメインのホワイトリストが定義されている場所ですか?そして、設定origin: trueはどのドメインにもアクセスを許可しますか?(npmjs.com/package/cors)@Doug Stevenson firebaseがクライアント/サーバーのhttps関数に必要な基本についてのドキュメントを作成できると思いますか?サンプルリポジトリは良好ですが、この余分な要件はありませんでした。
アラン

9
CORSサポートをバックエンドに追加したい人には、その結果とそれを適切に構成する方法を必ず理解してください。"origin:true"はテストには
最適です

1
Googleクラウド機能は、ワイルドカードの起源を許可しない:cloud.google.com/functions/docs/writing/...
コーリー・コール

73

あなたはこのようにクラウド機能でCORSを設定することができます

response.set('Access-Control-Allow-Origin', '*');

corsパッケージをインポートする必要はありません


2
これは私の場合、Mailchimp APIへのXHR呼び出しを行うクラウド関数に完全に機能します。
elverde

1
それが必要な答えです。
ジミー・ケイン

1
Googleクラウド機能は、ワイルドカードの起源を許可しない:cloud.google.com/functions/docs/writing/...
コーリー・コール

4
@CoreyCole ヘッダーを追加する必要がある場合のみだと思いますAuthorization。上記は問題なく動作するようです。
Stuart Memo

このコード行をどこに配置しますか?クラウド機能のどの部分ですか?
Antonio Ooi

41

Typescriptでこれをやろうとしている人にとっては、これはコードです:

import * as cors from 'cors';
const corsHandler = cors({origin: true});

export const exampleFunction= functions.https.onRequest(async (request, response) => {
       corsHandler(request, response, () => {});
       //Your code here
});

3
解決策は、クラウド機能のロギング(非常に悪い)と適切な非同期/待機機能を失うことになります。長いコールのコールバック内で関数のコンテンツが途中で終了する危険があります。
Oliver Dixon

2
Googleクラウド機能は、ワイルドカードの起源を許可しない:cloud.google.com/functions/docs/writing/...
コーリー・コール

29

しばらくしてからこれをググる人のために、もう1つの情報を追加します。firebaseホスティングを使用している場合は、リライトを設定して、たとえば(firebase_hosting_host)/ api / myfunctionのようなURLが( firebase_cloudfunctions_host)/ doStuff関数。このように、リダイレクトは透過的でサーバー側であるため、corsを処理する必要はありません。

これは、firebase.jsonのrewritesセクションで設定できます。

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]

1
imo、これは最良の答えです。追加のセキュリティ問題を追加せずに実際の問題を解決するためです。このようにして、クラウド機能は他のドメインと同じドメインから提供され、corsも必要ありません。
koljaTM

3
これは確かに優れた機能ですが、現在機能がデフォルトのリージョン(us-central1)に存在する場合にのみ機能します。レイテンシの理由で関数をeurope-west1にデプロイしたかったので、この問題に遭遇しました
Alex Suzuki

リダイレクトは正常に機能し、URLをよりクリーンにしますが、GETパラメーターを渡す方法がわかりません。関数(書き換え後)がパラメーターなしで呼び出されたようです。
royappa

20

CORSソリューションは私のために働いていません...今までのところ!

他の誰かが同じ問題に遭遇したかどうかはわかりませんが、私が見つけた例から5つの異なる方法でCORSを設定しましたが、何も機能しないようでした。Plunkerを使用して最小限の例を設定し、それが本当にバグであるかどうかを確認しましたが、例は美しく実行されました。私は、Firebaseの機能ログ(Firebaseコンソールにあります)をチェックして、それが何かを教えてくれるかどうかを確認することにしました。CORS関連ではなく、ノードサーバーコードいくつかのエラーがありました。デバッグすると、CORSエラーメッセージが表示されました。CORSに関係のないコードエラーがCORSエラー応答を返す理由はわかりませんが、それにより、間違ったウサギの穴をかなりの時間数だけダウンしました...

tl; dr-CORSソリューションが機能しない場合はfirebase関数ログを確認し、エラーがあればデバッグします


1
これは私を夢中にさせた。私の場合、それはコードのエラーでさえありませんでした!それがされた Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com ので、基本的には無料のクォータを超過したと機能がCORSエラーが返さ
Stanislau Buzunkoを

ここで数回発生すると、同じエラーがcorsだけでなくサーバーからも返されます。エラー:内部は基本的にエラーです。このエラーは、間違った関数を実行した場合にも発生します。たとえば、関数名の入力ミス
HenrikBøgelundLavstsen

クラウド機能内でGoogle reCAPTCHA検証をリクエストしようとすると、ブラウザーからCORSエラーもスローされます。Firebaseコンソールの機能ログを確認すると、と表示されていaccess to external network resources not allowed if the billing account is not enabledます。請求先アカウントを有効にすると、完全に機能します。これもcorsに関連しない例の1つですが、corsエラーがスローされます。
Antonio Ooi

19

@Andreysの質問に少し答えます。

cors(req, res, cb)関数内でコールバックを呼び出す必要はないようです。そのため、コールバックにすべてのコードを埋め込むことなく、関数の上部にあるcorsモジュールを呼び出すだけで済みます。後でcorsを実装する場合、これははるかに高速です。

exports.exampleFunction = functions.https.onRequest((request, response) => {
    cors(request, response, () => {});
    return response.send("Hello from Firebase!");
});

最初の投稿で述べたように、corsを初期化することを忘れないでください。

const cors = require('cors')({origin: true});


1
これは、ヘッダーを手動で設定して他のSOが応答しなかったときに機能しました
ジムファクター

これは機能しますが、有効にしていてFirebaseにデプロイできない場合、TSlintエラーが発生する可能性があります。それを克服するために応答cors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out

1
ここで2つのエラー。最初の1つ。cors関数の後のすべては2回実行されます(最初の要求はプリフライトであるため)。良くない。第2に、@ SpiralOutのソリューションでは、クラウド関数のログ記録が失われ(非常に悪い)、適切な非同期/待機機能がなくなり、関数のコンテンツがコールバック内で途中で終了する危険があります。
Oliver Dixon

@SpiralOutは、tslintを無効にすることができます
Vlad

1
昨年、gcfについて多くのことを学んだので、この回答はもうお勧めしません。迅速なプロトタイプには便利ですが、実際の製造ケースではこれを避けてください
Jaap Weijland

11

これは役に立ちます。Express(カスタムURL)でfirebase HTTPクラウド機能を作成しました

const express = require('express');
const bodyParser = require('body-parser');
const cors = require("cors");
const app = express();
const main = express();

app.post('/endpoint', (req, res) => {
    // code here
})

app.use(cors({ origin: true }));
main.use(cors({ origin: true }));
main.use('/api/v1', app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: false }));

module.exports.functionName = functions.https.onRequest(main);

書き換えセクションを追加したことを確認してください

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]

1
あなたの答えは私の友達が低すぎます。
Avram Virgil

ありがとう。@AvramVirgil
Sandy

これは最も迅速で簡単でした。ありがとうございます。
Gaurav Kakkar

8

それについて少しだけ発表しました:

https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html

通常、Express CORSパッケージを使用する必要があります。これには、GCF / Firebase関数の要件を満たすために少しハッキングが必要です。

お役に立てば幸いです。


4
ハッキングの意味がわかりませんか?少し詳しく説明しますか?あなたの投稿を読んでも、あなたがそれについて言及しているようには見えません
TheeBen

1
ここでcorsモジュールの作者。mhaligowskiを「ハッキング」するということは、Expressがミドルウェアを呼び出す方法と一致させるために、corsモジュールへの呼び出しをラップする必要があることを意味しました(つまり、req&resの後に3番目のパラメーターとして関数を指定します)
Troy

4

そこに私のような人がいる場合:クラウド関数と同じプロジェクトからクラウド関数を自分で呼び出したい場合は、firebase sdkを初期化してonCallメソッドを使用できます。それはあなたのためにすべてを扱います:

exports.newRequest = functions.https.onCall((data, context) => {
    console.log(`This is the received data: ${data}.`);
    return data;
})

この関数を次のように呼び出します。

// Init the firebase SDK first    
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);

Firebaseドキュメント:https : //firebase.google.com/docs/functions/callable

SDKを初期化できない場合、ここに他の提案の本質があります。


3
実際にブラウザでonCall funcを使用すると、corsエラーが発生しました。このリクエストでコストヘッダーを設定できますか?
Viktor Hardubej

4

「cors」ライブラリをインポートせずにcorsを有効にする方法が見つかりました。またTypescript、Chromeバージョン81.0 でも動作し、テストされています。

exports.createOrder = functions.https.onRequest((req, res) => {
// browsers like chrome need these headers to be present in response if the api is called from other than its base domain
  res.set("Access-Control-Allow-Origin", "*"); // you can also whitelist a specific domain like "http://127.0.0.1:4000"
  res.set("Access-Control-Allow-Headers", "Content-Type");

  // your code starts here

  //send response
  res.status(200).send();
});

3

価値があることについては、に渡ったときに同じ問題が発生していappましたonRequest。この問題は、firebase関数のリクエストURLの末尾のスラッシュにあることがわかりました。Expressが探していました'/'が、関数の末尾にスラッシュがありませんでした[project-id].cloudfunctions.net/[function-name]。CORSエラーは偽陰性でした。末尾にスラッシュを追加すると、期待した応答が得られました。


[project-id]これが私が直面した問題だったので、必ず追加してください
アンプラグド

3

私は私のリクエストで承認を持っているので、この方法のみが私のために機能します:

exports.hello = functions.https.onRequest((request, response) => {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); // vital
if (request.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    response.set('Access-Control-Allow-Methods', 'GET');
    response.set('Access-Control-Allow-Headers', 'Content-Type');
    response.set('Access-Control-Max-Age', '3600');
    response.status(204).send('');
} else {
    const params = request.body;
    const html = 'some html';
    response.send(html)
} )};

Googleクラウド機能は、ワイルドカードの起源を許可しない:cloud.google.com/functions/docs/writing/...
コーリー・コール

3

corsプラグインを使用しない/使用できない場合setCorsHeaders()は、ハンドラー関数で最初に関数を呼び出すこともできます。

また、返信するときは、responseSuccess / Error関数を使用します。

const ALLOWED_ORIGINS = ["http://localhost:9090", "https://sub.example.com", "https://example.com"]


// Set CORS headers for preflight requests
function setCorsHeaders (req, res) {
  var originUrl = "http://localhost:9090"


  if(ALLOWED_ORIGINS.includes(req.headers.origin)){
    originUrl = req.headers.origin
  }

  res.set('Access-Control-Allow-Origin', originUrl);
  res.set('Access-Control-Allow-Credentials', 'true');

  if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    res.set('Access-Control-Allow-Methods', 'GET,POST','PUT','DELETE');
    res.set('Access-Control-Allow-Headers', 'Bearer, Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  }
}

function respondError (message, error, code, res) {
  var response = {
    message: message,
    error: error
  }
  res.status(code).end(JSON.stringify(response));
}


function respondSuccess (result, res) {
  var response = {
    message: "OK",
    result: result
  }
  res.status(200).end(JSON.stringify(response));
}

2

Firebaseアプリをローカルでテストしている場合は、関数をlocalhostクラウドではなくポイントする必要があります。デフォルトでは、firebase serveまたはfirebase emulators:startWebアプリで使用するときに、関数がlocalhostではなくサーバーを指すようにします。

以下のスクリプトを、firebase initスクリプトの後にhtmlヘッドに追加します。

 <script>
      firebase.functions().useFunctionsEmulator('http://localhost:5001')
 </script> 

コードをサーバーにデプロイするときは、必ずこのスニペットを削除してください。


2

変更trueする"*"ことは私にとってトリックをしたので、これは次のようになります:

const cors = require('cors')({ origin: "*" })

一般に、この方法でこの応答ヘッダーを設定するため、このアプローチを試しました。

'Access-Control-Allow-Origin', '*'

これにより、すべてのドメインがエンドポイントを呼び出すことができるため、安全ではないことに注意してください。

さらに、ドキュメントで詳細を読むことができます:https : //github.com/expressjs/cors


1

Expressを使用していない場合、または単にCORSを使用したい場合。次のコードは解決に役立ちます

const cors = require('cors')({ origin: true, });   
exports.yourfunction = functions.https.onRequest((request, response) => {  
   return cors(request, response, () => {  
        // *Your code*
    });
});

0

私の場合、エラーはクラウド関数の呼び出し元によるアクセス制限が原因でした。クラウド関数呼び出し元にallUsersを追加してください。リンクをキャッチしてください。詳細は記事を参照してください


回答にリンクされた資料のいくつかの説明を提供してください、なぜそれが関連しているのかなど
Firefly

0

他の解決策がどれも機能しない場合は、呼び出しの最初に以下のアドレスを追加して、CORS-リダイレクトを有効にしてみてください。

https://cors-anywhere.herokuapp.com/

JQuery AJAXリクエストを使用したサンプルコード:

$.ajax({
   url: 'https://cors-anywhere.herokuapp.com/https://fir-agilan.web.app/gmail?mail=asd@gmail.com,
   type: 'GET'
});

0

私の経験を追加します。CORSエラーが発生した理由を見つけるために何時間も費やしました。

クラウド関数の名前を変更したことがあります(大きなアップグレード後に最初に試みていたものです)。

そのため、Firebaseアプリが誤った名前でクラウド関数を呼び出していた場合、CORSエラーではなく404エラーをスローするはずでした。

Firebaseアプリでクラウド関数名を修正すると、問題が修正されました。

これに関するバグレポートをここに記入しました https://firebase.google.com/support/troubleshooter/report/bugs

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.