Abilitazione di CORS nelle funzioni cloud per Firebase


141

Attualmente sto imparando come utilizzare le nuove funzioni cloud per Firebase e il problema che sto riscontrando è che non riesco ad accedere alla funzione che ho scritto tramite una richiesta AJAX. Ottengo l'errore "No 'Access-Control-Allow-Origin'". Ecco un esempio della funzione che ho scritto:

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

La funzione si trova in questo URL: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

I documenti di Firebase suggeriscono di aggiungere il middleware CORS all'interno della funzione, l'ho provato ma non funziona per me: https://firebase.google.com/docs/functions/http-events

Ecco come l'ho fatto:

var cors = require('cors');    

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

Che cosa sto facendo di sbagliato? Gradirei qualsiasi aiuto con questo.

AGGIORNARE:

La risposta di Doug Stevenson ha aiutato. Aggiungendo ({origin: true}) il problema è stato risolto, dovevo anche passare response.status(500)a quello response.status(200)che all'inizio mi mancava completamente.


Anche un esempio nei documenti qui
Kato

Ho alcune funzioni che funzionano con la soluzione fornita ma ora sto provando una nuova funzione che essenzialmente aggiunge grafici aperti nella parte superiore del mio index.html e restituisce index.html aggiornato e non riesco a farlo funzionare :( continua a ottenere l'errore ACCESS-CONTROL ---
TheeBen,

2
avvolgere la richiesta in arrivo in cors () come sopra era l'unica cosa che ha funzionato per me
Charles Harring il

puoi modificare il tuo "aggiornamento" per sottolineare la necessità del middleware cors? Questo farà risparmiare un po 'di tempo a qualcuno
Antoine Weber,

Risposte:


151

Esistono due funzioni di esempio fornite dal team di Firebase che dimostrano l'uso di CORS:

Il secondo esempio utilizza un modo diverso di lavorare con cors rispetto a quello attualmente in uso.

Inoltre, considera l'importazione in questo modo, come mostrato negli esempi:

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

2
Grazie! L'aggiunta ({origin: true}) ha aiutato.
Andrey Pokrovskiy,

2
Bene, hai sicuramente bisogno origin: truedi lasciarlo fuori perché questo non funzionerà
Scott

4
Sembra che sia qui che viene definita la whitelist dei domini per consentire l'accesso? E l'impostazione origin: trueconsente a qualsiasi dominio di accedere? ( npmjs.com/package/cors ) @Doug Stevenson Pensi che firebase potrebbe scrivere un documento sulle basi necessarie per le funzioni https client / server? Il repository dei campioni è buono, ma ci siamo persi questo ulteriore requisito.
Alan,

9
A chiunque sia disposto ad aggiungere il supporto CORS ai propri back-end: assicurarsi di averne compreso le conseguenze e come configurarlo correttamente. "origin: true" è interessante per i test ma
vanifica

1
Le funzioni cloud di Google non consentono l'origine jolly: cloud.google.com/functions/docs/writing/…
Corey Cole

73

È possibile impostare CORS nella funzione cloud in questo modo

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

Non è necessario importare il corspacchetto


2
Questo funziona perfettamente per il mio caso, una funzione cloud che effettua una chiamata XHR all'API Mailchimp.
elverde,

1
Questa è la risposta necessaria.
Jimmy Kane,

1
Le funzioni cloud di Google non consentono l'origine jolly: cloud.google.com/functions/docs/writing/…
Corey Cole

4
@CoreyCole Penso che sia solo se devi aggiungere l' Authorizationintestazione. Quanto sopra sembra funzionare bene.
Stuart Memo

Dove posizionare questa riga di codice? Quale parte della funzione cloud?
Antonio Ooi,

41

Per chiunque cerchi di farlo in Typescript questo è il codice:

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
La soluzione ti farà perdere l'accesso alle funzioni cloud (molto male) e la corretta funzionalità asincrona / attendi, rischi il fatto che il contenuto della funzione venga terminato prematuramente all'interno del callback per le chiamate lunghe.
Oliver Dixon,

2
Le funzioni cloud di Google non consentono l'origine jolly: cloud.google.com/functions/docs/writing/…
Corey Cole

29

Un'ulteriore informazione, solo per il gusto di chi cerca su Google dopo un po 'di tempo: se stai usando l'hosting firebase, puoi anche impostare riscritture, in modo che ad esempio un url come (firebase_hosting_host) / api / myfunction reindirizzi a ( firebase_cloudfunctions_host) / doStuff. In questo modo, poiché il reindirizzamento è trasparente e lato server, non è necessario gestire cors.

Puoi configurarlo con una sezione di riscrittura in firebase.json:

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

1
imo, questa è la risposta migliore, poiché risolve il problema reale senza aggiungere ulteriori problemi di sicurezza. In questo modo le funzioni cloud sono servite dallo stesso dominio degli altri e non hai nemmeno bisogno di alcun cors.
koljaTM,

3
Questa è davvero una grande funzionalità, ma attualmente funziona solo se le funzioni vivono nella regione predefinita (us-central1). Volevo implementare le mie funzioni in europe-west1 per motivi di latenza e ho riscontrato questo problema: github.com/firebase/firebase-tools/issues/842
Alex Suzuki,

Il reindirizzamento funziona bene e rende l'URL più pulito, ma non ho capito come passare i parametri GET. La funzione (dopo la riscrittura) sembra essere chiamata senza parametri.
Royappa,

20

Nessuna soluzione CORS ha funzionato per me ... fino ad ora!

Non sono sicuro che qualcun altro abbia riscontrato lo stesso problema, ma ho impostato CORS in 5 modi diversi dagli esempi che ho trovato e nulla sembrava funzionare. Ho creato un esempio minimo con Plunker per vedere se si trattava davvero di un bug, ma l'esempio ha funzionato magnificamente. Ho deciso di controllare i registri delle funzioni di firebase (trovati nella console di firebase) per vedere se questo potesse dirmi qualcosa. Ho avuto un paio di errori nel mio codice del server nodo , non correlato a CORS , che quando ho eseguito il debug mi ha rilasciato il mio messaggio di errore CORS . Non so perché gli errori di codice non correlati a CORS restituiscano una risposta di errore CORS, ma mi ha portato nella tana del coniglio sbagliata per un buon numero di ore ...

tl; dr - controlla i log delle tue funzioni firebase se nessuna soluzione CORS funziona e esegui il debug di eventuali errori


1
questo mi ha fatto impazzire. nel mio caso non è stato nemmeno un errore nel codice! era Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com così sostanzialmente superata la quota libera e le funzioni restituivano errore cors
Stanislau Buzunko,

Succede un paio di volte qui, lo stesso errore viene restituito dal server e cors: Errore: interno è sostanzialmente l'errore. Questo errore si verifica anche se si esegue la funzione errata, ad esempio digitando erroneamente il nome di una funzione
Henrik Bøgelund Lavstsen

Quando si tenta di richiedere la verifica di Google reCAPTCHA all'interno della funzione cloud, anche il browser genera l'errore CORS. Quando controllo il registro delle funzioni di Firebase Console, viene visualizzato access to external network resources not allowed if the billing account is not enabled. Dopo aver abilitato l'account di fatturazione, funziona perfettamente. Questo è anche uno degli esempi non correlati a cors, ma viene generato un errore cors.
Antonio Ooi,

19

Ho una piccola aggiunta alla risposta di @Andreys alla sua stessa domanda.

Sembra che non devi chiamare il callback nella cors(req, res, cb)funzione, quindi puoi semplicemente chiamare il modulo cors nella parte superiore della tua funzione, senza incorporare tutto il tuo codice nel callback. Questo è molto più veloce se vuoi implementare cors dopo.

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

Non dimenticare di avviare cors come indicato nel post di apertura:

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


1
questo ha funzionato quando altri SO rispondono impostando manualmente le intestazioni no
Jim Factor

Funziona ma può causare errori TSlint se lo avevi abilitato e non puoi distribuire su Firebase. Inserisci la risposta all'interno della chiusura del corsetto per superarlacors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out

1
2 errori qui ragazzi. Il primo. Qualunque cosa dopo la funzione cors verrà eseguita due volte (poiché la prima richiesta è preflight). Non bene. In secondo luogo, @SpiralOut la tua soluzione ti farà perdere l'accesso alle funzioni cloud (molto male) e la corretta funzionalità asincrona / attendi, rischiando che il contenuto della funzione venga terminato prematuramente all'interno del callback.
Oliver Dixon,

@SpiralOut puoi semplicemente disabilitare tslint
Vlad

1
Avendo imparato molto su gcf nell'ultimo anno, non consiglierei più questa risposta. Potrebbe essere utile per prototipi rapidi, ma
evitatelo in

11

Questo potrebbe essere utile. Ho creato la funzione cloud HTTP firebase con express (URL personalizzato)

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

Assicurati di aver aggiunto sezioni di riscrittura

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

1
La tua risposta è troppo bassa amico mio, la migliore risposta di gran lunga.
Avram Virgil,

Grazie. @AvramVirgil
Sandy,

Questo è stato il più rapido e semplice, grazie!
Gaurav Kakkar,

8

Ho appena pubblicato un piccolo pezzo su questo:

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

Generalmente, dovresti usare il pacchetto Express CORS , che richiede un po 'di hacking per soddisfare i requisiti delle funzioni GCF / Firebase.

Spero che aiuti!


4
Non sei sicuro di cosa intendi per hacking? Ti interessa elaborare un po '? Leggi il tuo post ma non ti vedo menzionarlo
TheeBen,

1
autore del modulo cors qui; "hacking" mhaligowski significava semplicemente che doveva avvolgere la chiamata al modulo cors per farla corrispondere al modo in cui Express chiama il middleware (ovvero fornire una funzione come terzo parametro dopo req & res)
Troy

4

Se ci sono persone come me là fuori: Se vuoi chiamare la funzione cloud dallo stesso progetto della funzione cloud stessa, puoi avviare firebase sdk e usare il metodo onCall. Gestirà tutto per te:

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

Chiamare questa funzione in questo modo:

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

Documenti Firebase: https://firebase.google.com/docs/functions/callable

Se non riesci ad avviare l'SDK, ecco l'essenza degli altri suggerimenti:


3
in realtà quando uso la funzione onCall sul browser ho ricevuto l'errore cors. Posso impostare intestazioni costom in questa richiesta?
Viktor Hardubej,

4

Trovato un modo per abilitare cors senza importare alcuna libreria "cors". Funziona anche con Typescripte testato nella versione 81.0 di Chrome.

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

Per quel che vale ho avuto lo stesso problema quando passa appin onRequest. Mi sono reso conto che il problema era una barra finale dell'URL della richiesta per la funzione Firebase. Express cercava '/'ma non avevo la barra finale della funzione [project-id].cloudfunctions.net/[function-name]. L'errore CORS era un falso negativo. Quando ho aggiunto la barra finale, ho ottenuto la risposta che mi aspettavo.


assicurati inoltre di aggiungere il tuo in [project-id]quanto questo è stato il problema che ho riscontrato
scollegato

3

Solo in questo modo funziona per me poiché ho l'autorizzazione nella mia richiesta:

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

Le funzioni cloud di Google non consentono l'origine jolly: cloud.google.com/functions/docs/writing/…
Corey Cole

3

Se non si utilizza / non è possibile utilizzare il plug-in cors, anche la chiamata della setCorsHeaders()funzione prima nella funzione gestore funzionerà.

Utilizzare anche le funzioni respondSuccess / Error quando si risponde.

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

Se stai testando l'app Firebase localmente, devi puntare alle funzioni localhostanziché al cloud. Per impostazione predefinita, firebase serveo firebase emulators:startpunta le funzioni al server anziché a localhost quando lo si utilizza nella propria app Web.

Aggiungi lo script seguente in testa html dopo lo script init di firebase:

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

Assicurati di rimuovere questo frammento durante la distribuzione del codice sul server.


2

Cambiando truedal "*"fatto il trucco per me, quindi questo è come sembra:

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

Ho provato questo approccio perché, in generale, è impostato questo header di risposta:

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

Tenere presente che ciò consentirà a qualsiasi dominio di chiamare gli endpoint, pertanto NON è sicuro.

Inoltre, puoi leggere di più sui documenti: https://github.com/expressjs/cors


1

Se non si utilizza Express o si desidera semplicemente utilizzare CORS. Il seguente codice aiuterà a risolvere

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

0

Nel mio caso l'errore è stato causato dall'accesso al limite di invoker della funzione cloud. Aggiungi tutti gli utenti all'invocatore di funzioni cloud. Si prega di prendere il collegamento . Per ulteriori informazioni, consultare l' articolo


Fornisci una spiegazione del materiale collegato nella tua risposta, perché è pertinente e così via
Firefly

0

Se nessuna delle altre soluzioni funziona, puoi provare ad aggiungere l'indirizzo sotto all'inizio della chiamata per abilitare CORS - reindirizzamento:

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

Codice di esempio con richiesta JQuery AJAX:

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

0

Aggiungendo la mia esperienza. Ho passato ore a cercare di scoprire perché avevo un errore CORS.

Succede che ho rinominato la mia funzione cloud (il primo che stavo provando dopo un grande aggiornamento).

Quindi, quando la mia app firebase stava chiamando la funzione cloud con un nome errato, avrebbe dovuto generare un errore 404, non un errore CORS.

La correzione del nome della funzione cloud nella mia app firebase ha risolto il problema.

Ho compilato una segnalazione di bug al riguardo qui https://firebase.google.com/support/troubleshooter/report/bugs

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.