Aktivieren von CORS in Cloud-Funktionen für Firebase

140

Ich lerne gerade, wie man neue Cloud-Funktionen für Firebase verwendet, und das Problem ist, dass ich nicht auf die Funktion zugreifen kann, die ich über eine AJAX-Anfrage geschrieben habe. Ich erhalte den Fehler "No 'Access-Control-Allow-Origin'". Hier ist ein Beispiel für die Funktion, die ich geschrieben habe:

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

Die Funktion befindet sich in dieser URL: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

In den Firebase-Dokumenten wird vorgeschlagen, CORS-Middleware in die Funktion aufzunehmen. Ich habe es versucht, aber es funktioniert bei mir nicht: https://firebase.google.com/docs/functions/http-events

So habe ich es gemacht:

var cors = require('cors');    

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

Was mache ich falsch? Ich würde mich über jede Hilfe freuen.

AKTUALISIEREN:

Doug Stevensons Antwort half. Durch Hinzufügen von ({origin: true}) wurde das Problem behoben. Ich musste auch wechseln response.status(500), response.status(200)was ich zunächst komplett verpasst hatte.

Andrey Pokrovskiy
quelle
Auch ein Beispiel in den Dokumenten hier
Kato
Ich habe einige Funktionen, die mit der bereitgestellten Lösung funktionieren, aber jetzt versuche ich eine neue Funktion, die im Wesentlichen offene Diagramme am Anfang meiner index.html hinzufügt und die aktualisierte index.html zurückgibt, und ich kann sie nicht zum Laufen bringen :( weiter erhalten die ACCESS-CONTROL --- Fehler
TheeBen
2
Das Eingehen der eingehenden Anfrage in cors () wie oben war das einzige, was für mich funktioniert hat
Charles Harring
Können Sie Ihr "Update" bearbeiten, um zu unterstreichen, dass die cors-Middleware erforderlich ist? Dies wird einigen Menschen Zeit sparen
Antoine Weber

Antworten:

151

Das Firebase-Team stellt zwei Beispielfunktionen zur Verfügung, die die Verwendung von CORS demonstrieren:

Im zweiten Beispiel wird anders mit Cors gearbeitet als derzeit.

Ziehen Sie auch in Betracht, wie folgt zu importieren, wie in den Beispielen gezeigt:

const cors = require('cors')({origin: true});
Doug Stevenson
quelle
2
Danke dir! Das Hinzufügen ({origin: true}) hat geholfen.
Andrey Pokrovskiy
2
Schön, Sie müssen auf jeden Fall, origin: trueda das Weglassen dazu führen wird, dass dies nicht funktioniert
Scott
4
Es sieht so aus, als ob hier die Whitelist der Domains definiert ist, die den Zugriff ermöglichen sollen. Und die Einstellung origin: trueermöglicht es jeder Domain, darauf zuzugreifen? ( npmjs.com/package/cors ) @Doug Stevenson Glaubst du, Firebase könnte ein Dokument über die Grundlagen schreiben, die für Client / Server-https-Funktionen benötigt werden? Das Samples Repo ist gut, aber wir hatten dieses zusätzliche Bedürfnis verpasst.
Alan
9
Für alle, die bereit sind, ihren Backends CORS-Unterstützung hinzuzufügen: Stellen Sie sicher, dass Sie die Konsequenzen verstehen und wissen, wie Sie diese richtig konfigurieren. "origin: true" ist cool zum Testen, aber es macht den ganzen Zweck
zunichte
1
Google Cloud-Funktionen erlauben nicht den Platzhalter-Ursprung: cloud.google.com/functions/docs/writing/…
Corey Cole
73

Sie können das CORS in der Cloud-Funktion wie folgt einstellen

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

Das corsPaket muss nicht importiert werden

Deanwilliammills
quelle
2
Dies funktioniert perfekt für meinen Fall, eine Cloud-Funktion, die einen XHR-Aufruf der Mailchimp-API ausführt.
Elverde
1
Das ist die Antwort, die benötigt wird.
Jimmy Kane
1
Google Cloud-Funktionen erlauben nicht den Platzhalter-Ursprung: cloud.google.com/functions/docs/writing/…
Corey Cole
4
@CoreyCole Ich denke , das ist nur, wenn Sie den AuthorizationHeader hinzufügen müssen . Das obige scheint in Ordnung zu funktionieren.
Stuart Memo
Wo soll diese Codezeile platziert werden? Welcher Teil der Cloud funktioniert?
Antonio Ooi
41

Für alle, die dies in Typescript versuchen, ist dies der Code:

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
});
Yayo Arellano
quelle
3
Durch die Lösung verlieren Sie die Anmeldung bei Cloud-Funktionen (sehr schlecht) und die ordnungsgemäße Async / Wait-Funktionalität. Bei langen Aufrufen besteht die Gefahr, dass der Funktionsinhalt innerhalb des Rückrufs vorzeitig beendet wird.
Oliver Dixon
2
Google Cloud-Funktionen erlauben nicht den Platzhalter-Ursprung: cloud.google.com/functions/docs/writing/…
Corey Cole
29

Eine zusätzliche Information, nur um dies nach einiger Zeit zu googeln: Wenn Sie Firebase-Hosting verwenden, können Sie auch Umschreibungen einrichten, sodass beispielsweise eine URL wie (firebase_hosting_host) / api / myfunction zu ( firebase_cloudfunctions_host) / doStuff-Funktion. Auf diese Weise müssen Sie sich nicht mit cors befassen, da die Umleitung transparent und serverseitig ist.

Sie können dies mit einem Umschreibeabschnitt in firebase.json einrichten:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
Pablo Urquiza
quelle
1
Imo, dies ist die beste Antwort, da sie das eigentliche Problem löst, ohne zusätzliche Sicherheitsprobleme hinzuzufügen. Auf diese Weise werden die Cloud-Funktionen von derselben Domäne wie die anderen bereitgestellt, und Sie benötigen nicht einmal Cors.
KoljaTM
3
Dies ist zwar eine großartige Funktion, funktioniert aber derzeit nur, wenn sich die Funktionen in der Standardregion (us-central1) befinden. Ich wollte meine Funktionen aus Latenzgründen in Europa-West1 bereitstellen und stieß auf dieses Problem: github.com/firebase/firebase-tools/issues/842
Alex Suzuki
Die Umleitung funktioniert einwandfrei und macht die URL sauberer, aber ich habe nicht herausgefunden, wie GET-Parameter übergeben werden. Die Funktion (nach dem Umschreiben) scheint ohne Parameter aufgerufen zu werden.
Royappa
20

Bei mir haben keine CORS-Lösungen funktioniert ... bis jetzt!

Ich bin mir nicht sicher, ob jemand anderes auf dasselbe Problem gestoßen ist wie ich, aber ich habe CORS auf fünf verschiedene Arten eingerichtet, anhand von Beispielen, die ich gefunden habe, und nichts schien zu funktionieren. Ich habe mit Plunker ein minimales Beispiel erstellt, um zu sehen, ob es wirklich ein Fehler war, aber das Beispiel lief wunderbar. Ich beschloss, die Firebase-Funktionsprotokolle (in der Firebase-Konsole) zu überprüfen, um festzustellen, ob mir das etwas sagen könnte. Ich hatte ein paar Fehler in meinem Knotenservercode , die nicht mit CORS zusammenhängen , und die mich beim Debuggen von meiner CORS-Fehlermeldung befreit haben . Ich weiß nicht, warum Codefehler, die nichts mit CORS zu tun haben, eine CORS-Fehlerantwort zurückgeben, aber sie haben mich eine gute Anzahl von Stunden lang in das falsche Kaninchenloch geführt ...

tl; dr - Überprüfen Sie Ihre Firebase-Funktionsprotokolle, wenn keine CORS-Lösungen funktionieren, und debuggen Sie eventuelle Fehler

tbone849
quelle
1
das hat mich verrückt gemacht. in meinem Fall war es nicht einmal ein Fehler im Code! es war Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com so im Grunde freie Quote wurde überschritten und Funktionen zurückgegeben cors Fehler
Stanislau Buzunko
Passiert hier ein paar Mal, wird der gleiche Fehler vom Server sowie cors zurückgegeben: Fehler: intern ist im Grunde der Fehler. Dieser Fehler tritt auch auf, wenn Sie die falsche Funktion ausführen, z. B. einen Funktionsnamen falsch eingeben
Henrik Bøgelund Lavstsen,
Wenn Sie versuchen, eine Google reCAPTCHA-Überprüfung innerhalb der Cloud-Funktion anzufordern, gibt der Browser auch den CORS-Fehler aus. Wenn ich das Funktionsprotokoll der Firebase-Konsole überprüfe, heißt es access to external network resources not allowed if the billing account is not enabled. Nach dem Aktivieren des Abrechnungskontos funktioniert es einwandfrei. Dies ist auch eines der nicht mit Cors zusammenhängenden Beispiele, es wird jedoch ein Cors-Fehler ausgegeben.
Antonio Ooi
19

Ich habe eine kleine Ergänzung zu @Andreys Antwort auf seine eigene Frage.

Es scheint, dass Sie den Rückruf in der cors(req, res, cb)Funktion nicht aufrufen müssen. Sie können also einfach das cors-Modul oben in Ihrer Funktion aufrufen, ohne den gesamten Code in den Rückruf einzubetten. Dies ist viel schneller, wenn Sie cors anschließend implementieren möchten.

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

Vergessen Sie nicht, cors wie im Eröffnungsbeitrag erwähnt zu initiieren:

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

Jaap Weijland
quelle
1
Dies funktionierte, wenn andere SO-Antworten mit manuellem Setzen der Header dies nicht taten
Jim Factor
Dies funktioniert, kann jedoch einen TSlint-Fehler verursachen, wenn Sie ihn aktiviert haben und nicht für Firebase bereitstellen können. Legen Sie die Antwort in den Cors-Verschluss, um sie zu überwindencors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out
1
2 Fehler hier Jungs. Erster. Alles nach der cors-Funktion wird zweimal ausgeführt (da die erste Anforderung Preflight ist). Nicht gut. Zweitens: @SpiralOut Ihre Lösung führt dazu, dass Sie die Anmeldung bei Cloud-Funktionen (sehr schlecht) und die ordnungsgemäße Async / Wait-Funktionalität verlieren. Sie riskieren, dass der Funktionsinhalt innerhalb des Rückrufs vorzeitig beendet wird.
Oliver Dixon
@SpiralOut können Sie einfach tslint deaktivieren
Vlad
1
Nachdem ich im letzten Jahr viel über gcf gelernt habe, würde ich diese Antwort nicht mehr empfehlen. Es könnte für schnelle Prototypen nützlich sein, aber vermeiden Sie dies in realen Produktionsfällen
Jaap Weijland
11

Dies könnte hilfreich sein. Ich habe eine Firebase-HTTP-Cloud-Funktion mit Express (benutzerdefinierte URL) erstellt.

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);

Bitte stellen Sie sicher, dass Sie Abschnitte zum Umschreiben hinzugefügt haben

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]
Sandig
quelle
1
Deine Antwort ist zu niedrig, mein Freund, die beste Antwort bei weitem.
Avram Virgil
Vielen Dank. @ AvramVirgil
Sandy
Das war am schnellsten und einfachsten, danke!
Gaurav Kakkar
8

Ich habe gerade ein kleines Stück darüber veröffentlicht:

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

Im Allgemeinen sollten Sie das Express CORS-Paket verwenden , das ein wenig herumhacken muss, um die Anforderungen in den GCF / Firebase-Funktionen zu erfüllen.

Hoffentlich hilft das!

mhaligowski
quelle
4
Nicht sicher, was du mit Hacken meinst? Möchtest du etwas näher darauf eingehen? Lesen Sie Ihren Beitrag, aber ich sehe nicht, dass Sie ihn erwähnen
TheeBen
1
Autor des cors-Moduls hier; durch "hacken" bedeutete mhaligowski einfach, dass er den aufruf an das cors-modul umbrechen musste, damit er mit der aufforderung von express Middleware übereinstimmt (dh eine funktion als dritter parameter nach req & res bereitstellt)
Troy
4

Wenn es Leute wie mich gibt: Wenn Sie die Cloud-Funktion aus demselben Projekt wie die Cloud-Funktion selbst aufrufen möchten, können Sie die firebase sdk initiieren und die onCall-Methode verwenden. Es wird alles für Sie erledigen:

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

Rufen Sie diese Funktion folgendermaßen auf:

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

Firebase-Dokumente: https://firebase.google.com/docs/functions/callable

Wenn Sie das SDK nicht initiieren können, ist hier die Essenz der anderen Vorschläge:

Chronnie
quelle
3
Wenn ich onCall func im Browser verwende, wird der Fehler cors angezeigt. Könnte ich in dieser Anfrage Costom-Header setzen?
Viktor Hardubej
4

Es wurde eine Möglichkeit gefunden, cors zu aktivieren, ohne eine 'cors'-Bibliothek zu importieren. Es funktioniert auch mit Typescriptund testete es in Chrome Version 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();
});
JerryGoyal
quelle
3

Für was es wert habe ich das gleiche Problem bei der Übergabe appin onRequest. Ich erkannte, dass das Problem ein abschließender Schrägstrich in der Anforderungs-URL für die Firebase-Funktion war. Express suchte, '/'aber ich hatte nicht den abschließenden Schrägstrich auf der Funktion [project-id].cloudfunctions.net/[function-name]. Der CORS-Fehler war falsch negativ. Als ich den abschließenden Schrägstrich hinzufügte, erhielt ich die erwartete Antwort.

Shadyhill
quelle
Stellen Sie auch sicher, dass Sie Ihre hinzufügen, [project-id]da dies das Problem war, mit dem ich konfrontiert war
unplugged
3

Nur so funktioniert es für mich, da ich eine Autorisierung in meiner Anfrage habe:

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)
} )};
Gleb Dolzikov
quelle
Google Cloud-Funktionen erlauben nicht den Platzhalter-Ursprung: cloud.google.com/functions/docs/writing/…
Corey Cole
3

Wenn Sie das cors-Plugin nicht verwenden können / können, setCorsHeaders()funktioniert es auch , die Funktion als erstes in der Handler-Funktion aufzurufen .

Verwenden Sie auch die AntwortenSuccess / Error-Funktionen, wenn Sie antworten.

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));
}
KasparTr
quelle
2

Wenn Sie die Firebase-App lokal testen, müssen Sie Funktionen localhostanstelle der Cloud anzeigen. Standardmäßig firebase serveoderfirebase emulators:start zeigt die Funktionen auf den Server anstatt auf localhost, wenn Sie sie in Ihrer Web-App verwenden.

Fügen Sie das folgende Skript im HTML-Kopf nach dem Firebase-Init-Skript hinzu:

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

Stellen Sie sicher, dass Sie dieses Snippet entfernen, wenn Sie Code auf dem Server bereitstellen.

JerryGoyal
quelle
2

Das Ändern truevon "*"hat den Trick für mich getan, also sieht es so aus:

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

Ich habe diesen Ansatz ausprobiert, weil im Allgemeinen so der Antwortheader festgelegt wird:

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

Beachten Sie, dass jede Domain Ihre Endpunkte aufrufen kann, daher ist sie NICHT sicher.

Weitere Informationen finden Sie in den Dokumenten: https://github.com/expressjs/cors

rauben
quelle
1

Wenn Sie Express nicht verwenden oder einfach nur CORS verwenden möchten. Der folgende Code hilft bei der Lösung

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

In meinem Fall wurde der Fehler durch den Zugriffsbeschränker der Cloud-Funktion verursacht. Bitte fügen Sie allUsers zum Cloud Function Invoker hinzu. Bitte fangen Sie den Link . Weitere Informationen finden Sie im Artikel

Kacpero
quelle
Bitte geben Sie in Ihrer Antwort einige Erklärungen zu verlinktem Material an, warum es relevant ist und so
Firefly
0

Wenn keine der anderen Lösungen funktioniert, können Sie versuchen, zu Beginn des Aufrufs die folgende Adresse hinzuzufügen, um die CORS-Umleitung zu aktivieren:

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

Beispielcode mit JQuery AJAX-Anforderung:

$.ajax({
   url: 'https://cors-anywhere.herokuapp.com/https://fir-agilan.web.app/[email protected],
   type: 'GET'
});
Agilan I.
quelle
0

Ich füge meine Erfahrung hinzu. Ich habe stundenlang versucht herauszufinden, warum ich einen CORS-Fehler hatte.

Es kommt vor, dass ich meine Cloud-Funktion umbenannt habe (das allererste, was ich nach einem großen Upgrade versucht habe).

Wenn meine Firebase-App die Cloud-Funktion mit einem falschen Namen aufrief, sollte sie einen 404-Fehler und keinen CORS-Fehler auslösen.

Das Problem wurde behoben, indem der Name der Cloud-Funktion in meiner Firebase-App behoben wurde.

Ich habe hier einen Fehlerbericht unter https://firebase.google.com/support/troubleshooter/report/bugs ausgefüllt

Thomas
quelle