Włączanie CORS w Cloud Functions dla Firebase

157

Obecnie uczę się, jak korzystać z nowych funkcji Cloud Functions dla Firebase, a problem, który mam, polega na tym, że nie mogę uzyskać dostępu do funkcji, którą napisałem, za pośrednictwem żądania AJAX. Pojawia się błąd „Nie 'Access-Control-Allow-Origin'”. Oto przykład funkcji, którą napisałem:

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

Funkcja znajduje się w tym adresie URL: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

Dokumentacja Firebase sugeruje dodanie oprogramowania pośredniczącego CORS do funkcji, próbowałem, ale to nie działa dla mnie: https://firebase.google.com/docs/functions/http-events

Oto jak to zrobiłem:

var cors = require('cors');    

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

Co ja robię źle? Byłbym wdzięczny za każdą pomoc w tym.

AKTUALIZACJA:

Odpowiedź Douga Stevensona pomogła. Dodanie ({origin: true}) rozwiązało problem, musiałem też zmienić, response.status(500)do response.status(200)którego początkowo całkowicie tęskniłem.

Andrey Pokrovskiy
źródło
Również próbka w dokumentach tutaj
Kato
Mam kilka funkcji, które działają z dostarczonym rozwiązaniem, ale teraz próbuję nowej funkcji, która zasadniczo dodaje otwarte wykresy na początku mojego pliku index.html i zwraca zaktualizowany index.html i nie mogę go uruchomić :( ACCESS-CONTROL --- błąd
TheeBen
2
zawijanie przychodzącej prośby w cors () jak powyżej było jedyną rzeczą, która działała dla mnie
Charles Harring
Czy możesz edytować swoją „aktualizację”, aby podkreślić, że oprogramowanie pośredniczące cors jest wymagane? To zaoszczędzi niektórym ludziom trochę czasu
Antoine Weber

Odpowiedzi:

166

Istnieją dwie przykładowe funkcje udostępnione przez zespół Firebase, które demonstrują użycie CORS:

Druga próbka wykorzystuje inny sposób pracy z kordami niż obecnie.

Rozważ importowanie w ten sposób, jak pokazano na przykładach:

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

Ogólna forma twojej funkcji będzie wyglądać następująco:

exports.fn = functions.https.onRequest((req, res) => {
    cors(req, res, () => {
        // your function body here - use the provided req and res from cors
    })
});
Doug Stevenson
źródło
2
Dziękuję Ci! Dodanie ({origin: true}) pomogło.
Andrey Pokrovskiy
4
Wygląda na to, że w tym miejscu zdefiniowano białą listę domen umożliwiających dostęp? A ustawienie origin: trueumożliwia dostęp dowolnej domenie? ( npmjs.com/package/cors ) @Doug Stevenson Czy myślisz, że Firebase mógłby napisać dokument o podstawach potrzebnych do obsługi funkcji https klient / serwer? Repozytorium sampli jest dobre, ale przegapiliśmy ten dodatkowy element.
Alan
11
Dla każdego, kto chce dodać obsługę CORS do swoich backendów: upewnij się, że rozumiesz konsekwencje i jak poprawnie ją skonfigurować. „origin: true” jest fajny do testów, ale pokonuje cały cel :)
dSebastien
1
funkcje w chmurze google nie zezwalają na pochodzenie symboli wieloznacznych: cloud.google.com/functions/docs/writing/ ...
Corey Cole
1
Przypomnienie dla wszystkich, którzy nadal importują cory, takie jak wspaniale wspomniał Doug, nie zapomnij o zawinięciu odpowiedzi, jak zrobił to Andrey, w przeciwnym razie to nie zadziała!
Gustavo Garcia
79

Możesz ustawić CORS w funkcji chmury w ten sposób

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

Nie ma potrzeby importowania corspakietu

deanwilliammills
źródło
2
Działa to idealnie w moim przypadku, funkcja chmury, która wykonuje wywołanie XHR do Mailchimp API.
elverde
1
To jest potrzebna odpowiedź.
Jimmy Kane
1
funkcje w chmurze google nie zezwalają na pochodzenie symboli wieloznacznych: cloud.google.com/functions/docs/writing/ ...
Corey Cole
4
@CoreyCole Myślę , że to tylko wtedy, gdy musisz dodać Authorizationnagłówek. Wydaje się, że powyższe działa poprawnie.
Stuart Memo
1
Dodałem tę linię do mojej funkcji w chmurze, a pobieranie mojego hosta lokalnego jest nadal blokowane przez zasady CORS.
elersong
46

Dla każdego, kto próbuje to zrobić w skrypcie Typescript, jest to kod:

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
źródło
3
Rozwiązanie sprawi, że stracisz logowanie się do funkcji chmury (bardzo źle) i poprawną funkcjonalność async / await, ryzykujesz, że zawartość funkcji zostanie przedwcześnie zakończona wewnątrz wywołania zwrotnego w przypadku długich wywołań.
Oliver Dixon
2
funkcje w chmurze google nie zezwalają na pochodzenie symboli wieloznacznych: cloud.google.com/functions/docs/writing/ ...
Corey Cole
29

Dodatkowa informacja, tylko ze względu na tych, którzy szukają tego po pewnym czasie: Jeśli korzystasz z hostingu Firebase, możesz również skonfigurować przepisywanie, aby na przykład adres URL taki jak (firebase_hosting_host) / api / myfunction przekierował do ( firebase_cloudfunctions_host) / doStuff. W ten sposób, ponieważ przekierowanie jest przezroczyste i po stronie serwera, nie musisz zajmować się procesorami.

Możesz to ustawić za pomocą sekcji przepisywania w firebase.json:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
Pablo Urquiza
źródło
1
imo, to najlepsza odpowiedź, ponieważ rozwiązuje rzeczywisty problem bez dodawania dodatkowych problemów z bezpieczeństwem. W ten sposób funkcje chmury są obsługiwane z tej samej domeny co reszta i nie potrzebujesz nawet żadnych corsów.
koljaTM
3
Jest to rzeczywiście świetna funkcja, ale obecnie działa tylko wtedy, gdy funkcje znajdują się w regionie domyślnym (us-central1). Chciałem wdrożyć moje funkcje na europe-west1 ze względu na opóźnienia i napotkałem ten problem: github.com/firebase/firebase-tools/issues/842
Alex Suzuki
Przekierowanie działa dobrze i sprawia, że ​​adres URL jest czystszy, ale nie wiem, jak przekazywać parametry GET. Funkcja (po przepisaniu) wydaje się być wywoływana bez parametrów.
royappa
20

Mam mały dodatek do odpowiedzi @Andreys na jego własne pytanie.

Wygląda na to, że nie musisz wywoływać funkcji zwrotnej w cors(req, res, cb)funkcji, więc możesz po prostu wywołać moduł cors u góry funkcji, bez osadzania całego kodu w funkcji zwrotnej. Jest to znacznie szybsze, jeśli chcesz później wdrożyć cors.

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

Nie zapomnij zainicjować cors, jak wspomniano w poście otwierającym:

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

Jaap Weijland
źródło
1
to działało, gdy inne odpowiedzi SO dotyczące ręcznego ustawiania nagłówków nie działały
Jim Factor
To działa, ale może spowodować błąd TSlint, jeśli był włączony i nie możesz wdrożyć w firebase. Umieść odpowiedź w zamknięciu cors, aby go przezwyciężyćcors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out
1
2 błędy tutaj chłopaki. Pierwszy. Wszystko po funkcji cors zostanie uruchomione dwukrotnie (ponieważ pierwsze żądanie dotyczy inspekcji wstępnej). Niedobrze. Po drugie, @SpiralOut Twoje rozwiązanie sprawi, że stracisz logowanie do funkcji chmury (bardzo źle) i prawidłową funkcjonalność async / await, ryzykujesz, że zawartość funkcji zostanie przedwcześnie zakończona w wywołaniu zwrotnym.
Oliver Dixon
@SpiralOut możesz po prostu wyłączyć tslint
Vlad
2
Dowiedziałem się wiele o gcf w zeszłym roku, więc nie polecałbym już tej odpowiedzi. Może się przydać w przypadku szybkich prototypów, ale unikaj tego w rzeczywistych przypadkach produkcyjnych
Jaap Weijland
20

Żadne rozwiązania CORS nie działały dla mnie ... do teraz!

Nie jestem pewien, czy ktoś inny napotkał ten sam problem, co ja, ale skonfigurowałem CORS na 5 różnych sposobów z przykładów, które znalazłem, i wydawało się, że nic nie działa. Ustawiłem minimalny przykład z Plunkerem, aby sprawdzić, czy to naprawdę błąd, ale przykład działał pięknie. Postanowiłem sprawdzić dzienniki funkcji Firebase (znalezione w konsoli Firebase), aby sprawdzić, czy to może mi coś powiedzieć. Wystąpiło kilka błędów w kodzie mojego serwera węzła , które nie były związane z CORS , które podczas debugowania zwolniły mój komunikat o błędzie CORS . Nie wiem, dlaczego błędy kodu niezwiązane z CORS zwracają odpowiedź błędu CORS, ale doprowadziło mnie to do niewłaściwej króliczej nory przez dobrą liczbę godzin ...

tl; dr - sprawdź dzienniki funkcji Firebase, jeśli żadne rozwiązania CORS nie działają, i debuguj wszelkie błędy, które masz

tbone849
źródło
2
to doprowadziło mnie do szału. w moim przypadku nie był to nawet błąd w kodzie! było Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com więc w zasadzie wolna kwota została przekroczona i funkcje zwrócił błąd Cors
Stanisław Buzunko
Zdarzyło się tutaj kilka razy, ten sam błąd jest zwracany z serwera, jak również cors: Błąd: wewnętrzny to w zasadzie błąd. Ten błąd wystąpi również, jeśli uruchomisz niewłaściwą funkcję, na przykład
błędnie wpisujesz
Kiedy próbujesz poprosić o weryfikację Google reCAPTCHA w ramach funkcji chmury, przeglądarka również wyświetla błąd CORS. Kiedy sprawdzam dziennik funkcji konsoli Firebase, mówi access to external network resources not allowed if the billing account is not enabled. Po włączeniu konta rozliczeniowego działa idealnie. Jest to również jeden z przykładów niezwiązanych z cors, ale wyrzucany jest błąd cors.
Antonio Ooi
11

To może być pomocne. Stworzyłem funkcję chmury Firebase HTTP z Express (niestandardowy adres URL)

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

Upewnij się, że dodałeś sekcje przepisywania

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]
Piaszczysty
źródło
1
Twoja odpowiedź jest zbyt niska, przyjacielu, zdecydowanie najlepsza odpowiedź.
Avram Virgil
Dzięki. @AvramVirgil
Sandy
To było najszybsze i najłatwiejsze ze wszystkich. Dzięki!
Gaurav Kakkar
6

Właśnie opublikowałem mały artykuł na ten temat:

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

Ogólnie rzecz biorąc, powinieneś używać pakietu Express CORS , który wymaga trochę hakowania, aby spełnić wymagania GCF / Firebase Functions.

Mam nadzieję, że to pomoże!

mhaligowski
źródło
4
Nie wiesz, co masz na myśli, mówiąc o hakowaniu? Chcesz trochę rozwinąć? Przeczytaj swój post, ale nie widzę, żebyś o nim wspominał
TheeBen
1
autor modułu cors tutaj; przez "hackowanie" mhaligowskiego oznaczało po prostu, że musiał zawinąć wywołanie modułu cors, aby dopasować go do sposobu, w jaki Express wywołuje oprogramowanie pośrednie (tj. dostarcza funkcję jako trzeci parametr po req & res)
Troy
Ten link jest uszkodzony mhaligowski.github.io/blog/2017/03/10/… dlatego lepiej jest umieścić zawartość (podsumowanie) zasobów zewnętrznych niż linki zewnętrzne
rahulserver
6

Znalazłem sposób na włączenie oprogramowania cors bez importowania biblioteki „cors”. Działa również Typescripti przetestował go w wersji 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();
});
GorvGoyl
źródło
To zadziałało dla mnie, dodając res.set("Access-Control-Allow-Origin", "*"); tylko nie działało res.set("Access-Control-Allow-Headers", "Content-Type"); rozwiązało mój problem
Amina Darwish
To nie zadziałało, ponieważ nie obsługiwało metody OPTIONS „preflight check” przed żądaniem GET / POST. Musiałem przełączyć się na corspakiet (lub odtworzyć OPTIONSspecjalną odpowiedź, która
okazała
4

Tylko w ten sposób działa dla mnie, ponieważ mam autoryzację w mojej prośbie:

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
źródło
funkcje w chmurze google nie zezwalają na pochodzenie symboli wieloznacznych: cloud.google.com/functions/docs/writing/ ...
Corey Cole
4

Jeśli są ludzie tacy jak ja: Jeśli chcesz wywołać funkcję chmury z tego samego projektu, co sama funkcja chmury, możesz zainicjować sdk bazy firebase i użyć metody onCall. Poradzi sobie ze wszystkim za Ciebie:

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

Wywołaj tę funkcję w ten sposób:

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

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

Jeśli nie możesz zainicjować SDK, oto esencja innych sugestii:

Chronnie
źródło
4
faktycznie, kiedy używam funkcji onCall w przeglądarce, pojawia się błąd cors. Czy mogę ustawić nagłówki costom w tym żądaniu?
Viktor Hardubej
4

Jeśli nie możesz / nie możesz użyć wtyczki cors, setCorsHeaders()zadziała również wywołanie funkcji jako pierwszej rzeczy w funkcji obsługi.

Podczas odpowiadania użyj także funkcji respondSuccess / 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));
}
KasparTr
źródło
3

Cóż to jest warte, miałem ten sam problem podczas przechodzenia appdo onRequest. Uświadomiłem sobie, że problem dotyczy końcowego ukośnika w adresie URL żądania dla funkcji Firebase. Express szukał, '/'ale nie mam końcowego ukośnika w funkcji [project-id].cloudfunctions.net/[function-name]. Błąd CORS był fałszywie ujemny. Kiedy dodałem końcowy ukośnik, otrzymałem oczekiwaną odpowiedź.

zacienione wzgórze
źródło
upewnij się również, że dodałeś swój, [project-id]ponieważ był to problem, z którym miałem do czynienia
odłączony
2

Jeśli lokalnie testujesz aplikację Firebase, musisz wskazać funkcje localhostzamiast chmury. Domyślnie firebase servelub firebase emulators:startwskazuje funkcje na serwer zamiast hosta lokalnego, gdy używasz go w aplikacji sieci Web.

Dodaj poniższy skrypt w nagłówku html po skrypcie inicjującym firebase:

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

Pamiętaj, aby usunąć ten fragment kodu podczas wdrażania kodu na serwerze.

GorvGoyl
źródło
2

Zmiana trueprzez "*"załatwiła mi sprawę, więc tak to wygląda:

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

Wypróbowałem to podejście, ponieważ generalnie tak jest ustawiony ten nagłówek odpowiedzi:

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

Pamiętaj, że pozwoli to każdej domenie na wywoływanie twoich punktów końcowych, dlatego NIE jest to bezpieczne.

Dodatkowo możesz przeczytać więcej w dokumentach: https://github.com/expressjs/cors

Obrabować
źródło
1

Jeśli nie używasz Express lub po prostu chcesz używać CORS. Poniższy kod pomoże rozwiązać problem

const cors = require('cors')({ origin: true, });   
exports.yourfunction = functions.https.onRequest((request, response) => {  
   return cors(request, response, () => {  
        // *Your code*
    });
});
krishnazden
źródło
1

Proste rozwiązanie za pomocą panelu Google Cloud Console:

  1. Przejdź do panelu konsoli GCP:

https://console.cloud.google.com/home/dashboard

  1. Przejdź do menu

„Funkcje chmury” (sekcja „Oblicz”)

  1. Wybierz swoją funkcję chmury, np. „MyFunction”, po prawej stronie powinno pojawić się boczne menu pokazujące ustawienia kontroli dostępu do niej

  2. Kliknij „Add Member”, wpisz „allUsers” i wybierz rolę „Cloud Function Invoker”

  3. Zapisz to -> teraz na liście funkcji Twojej chmury powinna pojawić się uwaga „Zezwalaj na nieuwierzytelnione”

Dostęp jest teraz dostępny dla wszystkich z internetu z poprawną konfiguracją do projektu GCP lub Firebase. ( Uważaj )

dimib
źródło
0

W moim przypadku błąd był spowodowany ograniczeniem dostępu wywoływacza funkcji chmury. Dodaj allUsers do wywołującego funkcje chmury. Proszę złap link . Więcej informacji można znaleźć w artykule

Kacpero
źródło
Proszę podać w odpowiedzi jakieś wyjaśnienie powiązanego materiału, dlaczego jest on odpowiedni i taki
Firefly
0

Jeśli żadne z pozostałych rozwiązań nie działa, możesz spróbować dodać poniższy adres na początku połączenia, aby włączyć CORS - przekierowanie:

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

Przykładowy kod z żądaniem JQuery AJAX:

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

Dodaję moje doświadczenie. Spędziłem godziny, próbując znaleźć przyczynę błędu CORS.

Zdarza się, że zmieniłem nazwę mojej funkcji chmury (pierwsza, którą próbowałem po dużym uaktualnieniu).

Więc kiedy moja aplikacja Firebase wywoływała funkcję chmury z niepoprawną nazwą, powinna zgłosić błąd 404, a nie błąd CORS.

Naprawienie nazwy funkcji chmury w mojej aplikacji Firebase rozwiązało problem.

Wypełniłem tutaj raport o błędzie na ten temat https://firebase.google.com/support/troubleshooter/report/bugs

Tomasz
źródło