Увімкнення CORS у хмарних функціях для Firebase


141

В даний час я вчуся використовувати нові хмарні функції для Firebase, і проблема, яка у мене виникає, полягає в тому, що я не можу отримати доступ до функції, яку я написав через запит 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 пропонують додати проміжне програмне забезпечення 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'});
   })
})

Що я роблю неправильно? Буду вдячний за будь-яку допомогу в цьому.

ОНОВЛЕННЯ:

Відповідь Дуга Стівенсона допомогла. Додавання ({origin: true}) виправило проблему, я також повинен був змінити те, що response.status(500)спочатку response.status(200)я зовсім пропустив.


Також зразок в документах тут
Като

У мене є деякі функції, які працюють з наданим рішенням, але зараз я намагаюся нову функцію, яка по суті додає відкриті графіки до вершини мого index.html і повертає оновлений index.html, і я не можу змусити його працювати :( продовжувати отримувати помилка-КОНТРОЛЬ --- помилка
TheeBen

2
загортання вхідного запиту в корс (), як вище, було єдиним, що працювало для мене
Чарльз Харрінг,

чи можете ви відредагувати "оновлення", щоб підкреслити, що потрібне проміжне програмне забезпечення "cors"? Це врятує деяких людей деякий час
Антуан Вебер

Відповіді:


151

Команда Firebase пропонує дві вибіркові функції, які демонструють використання CORS:

Другий зразок використовує інший спосіб роботи з колесами, ніж ви зараз використовуєте.

Крім того, розгляньте можливість імпорту, як показано у зразках:

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

2
Дякую! Додавання ({origin: true}) допомогло.
Андрій Покровський

2
Приємно, вам точно потрібно, origin: trueоскільки це не призведе до того, що це не спрацює
Скотт

4
Схоже, саме тут визначено білий список доменів для дозволу доступу? А налаштування origin: trueдозволяє будь-якому домену отримати доступ? ( npmjs.com/package/cors ) @Doug Stevenson Ви вважаєте, що Firebase може написати документ про основи, необхідні для функцій https клієнт / сервер? РЕПО зразків добре, але ми пропустили цю зайву потребу.
Алан

9
Для всіх, хто бажає додати підтримку CORS до їхніх останніх: будь ласка, переконайтеся, що ви розумієте наслідки та як правильно їх налаштувати. "origin: true" - це цікаво для тестування, але воно перемагає цілі :)
dSebastien

1
хмарні функції google не дозволяють походження підстановки: cloud.google.com/functions/docs/writing/…
Corey Cole

73

Ви можете встановити CORS у такій хмарній функції

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

Не потрібно імпортувати corsпакет


2
Це прекрасно працює в моєму випадку - хмарна функція, яка робить виклик XHR в API Mailchimp.
Ельверде

1
Це потрібна відповідь.
Джиммі Кейн

1
хмарні функції google не дозволяють походження підстановки: cloud.google.com/functions/docs/writing/…
Corey Cole

4
@CoreyCole Я думаю, що це лише якщо вам потрібно додати Authorizationзаголовок. Згадане вище, здається, працює нормально.
Пам’ятка Стюарта

Де розмістити цей рядок коду? Яка частина хмарної функції?
Антоніо Оой

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
Рішення призведе до того, що ви втратите журнал на хмарних функціях (дуже погано) та належну функцію асинхронізації / очікування, ви ризикуєте, що вміст функції передчасно закінчиться всередині зворотного дзвінка при тривалих дзвінках.
Олівер Діксон

2
хмарні функції google не дозволяють походження підстановки: cloud.google.com/functions/docs/writing/…
Corey Cole

29

Ще один додатковий фрагмент інформації, просто заради тих, хто їх гуглить через деякий час: Якщо ви використовуєте хостинг Firebase, ви також можете налаштувати перезаписи, щоб, наприклад, URL-адреса типу (firebase_hosting_host) / api / myfunction перенаправляє на ( firebase_cloudfunctions_host) / doStuff функція. Таким чином, оскільки перенаправлення є прозорим і на стороні сервера, вам не доведеться мати справу з корсами.

Ви можете налаштувати це за допомогою розділу переписувань у firebase.json:

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

1
imo, це найкраща відповідь, оскільки вона вирішує фактичну проблему без додавання додаткових проблем із безпекою. Таким чином хмарні функції обслуговуються з того самого домену, що і решта, і вам навіть не потрібні корзи.
koljaTM

3
Це дійсно чудова функція, але вона наразі працює лише у тому випадку, якщо функції живуть у регіоні за замовчуванням (us-central1). Я хотів розгорнути свої функції на europe-west1 з причин затримки і зіткнувся з цим питанням: github.com/firebase/firebase-tools/isissue/842
Alex Suzuki

Перенаправлення працює чудово і робить URL-адресою чистішою, але я не зрозумів, як передавати параметри GET. Функція (після перезапису), здається, викликається без параметрів.
royappa

20

Жодне рішення CORS для мене не працювало ... досі!

Не впевнений, чи хтось інший зіткнувся з тією ж проблемою, що і я, але я встановив CORS, як 5 різних способів із знайдених нами прикладів, і, здається, нічого не працює. Я створив мінімальний приклад з Plunker, щоб побачити, чи справді це помилка, але приклад прекрасно працював. Я вирішив перевірити журнали функцій firebase (знаходяться на консолі firebase), щоб побачити, чи може це мені щось сказати. У мене в коді сервера вузла було кілька помилок , не пов'язаних з CORS , що коли я налагоджував, звільнив мене від мого повідомлення про помилку CORS . Я не знаю, чому помилки коду, не пов'язані з CORS, повертають відповідь на помилку CORS, але це призвело до того, що я пропустив неправильну кролячу дірку протягом досить багато годин ...

tl; dr - перевірте журнали функцій Firebase, якщо жодні рішення CORS не працюють, і налагодите будь-які помилки


1
це зводило мене з розуму. в моєму випадку це навіть не помилка в коді! це було, в Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com основному, перевищено вільну квоту, і функції повернули помилку
cors

Відбудьтесь пару разів, однакова помилка повертається з сервера так само, як і cors: Помилка: внутрішня - це в основному помилка. Ця помилка також трапиться, якщо ви запустили неправильну функцію, наприклад,
помиливши

Коли ви намагаєтеся подати запит на перевірку reCAPTCHA від Google у межах хмарної функції, браузер видасть і помилку CORS. Коли я перевіряю журнал функцій консолі Firebase, він говорить access to external network resources not allowed if the billing account is not enabled. Після ввімкнення рахунку для рахунків він працює бездоганно. Це також один із прикладів, що не стосуються корсів, але припускається помилка.
Антоніо Оой

19

У мене є невелике доповнення до відповіді @Andreys на його власне запитання.

Здається, що вам не потрібно викликати зворотний виклик у cors(req, res, cb)функції, тому ви можете просто зателефонувати модулю cors у верхній частині своєї функції, не вставляючи весь код у зворотний виклик. Це набагато швидше, якщо ви хочете згодом реалізувати корзи.

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

Не забувайте запускати кор, як згадувалося у вступному дописі:

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


1
це спрацювало, коли інші відповіді ТА із встановленням заголовків вручну не зробили
Джим Фактор

Це працює, але це може спричинити помилку TSlint, якщо ви його включили та не можете розгорнути до firebase. Покладіть відповідь всередину закриття корсів, щоб подолати їїcors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out

1
2 помилки тут, хлопці. Перший. Все, що відбудеться після функції «cors», запуститься двічі (оскільки перший запит є передпольотним). Не добре. По-друге, @SpiralOut ваше рішення змусить вас втратити реєстрацію хмарних функцій (дуже погано) та належну функцію асинхронізації / очікування, ви ризикуєте, що вміст функції передчасно закінчиться всередині зворотного виклику.
Олівер Діксон

@SpiralOut ви можете просто відключити tslint
Влад

1
Дізнавшись багато про gcf за останній рік, я більше не рекомендував би цю відповідь. Це може бути зручним для швидких прототипів, але уникайте цього в реальних виробничих випадках
Jaap Weijland

11

Це може бути корисним. Я створив хмарну функцію HTTP firebase з експресом (спеціальна 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);

Переконайтеся, що ви додали переписати розділи

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

1
Мій друже, твоя відповідь занадто низька, найкраща відповідь на сьогоднішній день.
Аврам Вергілій

Дякую. @AvramVirgil
Сенді

Це було найшвидше і найпростіше з усіх, Дякую!
Гаурав Какар

8

Я щойно опублікував невеличку деталь про це:

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

Як правило, вам слід скористатися пакетом Express CORS , який потребує невеликого злому, щоб відповідати вимогам функцій GCF / Firebase.

Сподіваюся, що це допомагає!


4
Не знаєте, що ви маєте на увазі під хакерством? Хочете трохи допрацювати? Прочитайте свій пост, але я не бачу, щоб ви його згадували
TheeBen

1
автор модуля cors тут; "хакерство" mhaligowski просто означало, що йому доведеться завершити виклик до модуля cors, щоб він відповідав тому, як Express викликує проміжне програмне забезпечення (тобто надає функцію як третій параметр після req & res)
Троя,

4

Якщо там є такі люди, як я: Якщо ви хочете викликати функцію хмари з того самого проекту, що і хмара, він функціонує самостійно, ви можете запустити sdk firebase і використовувати метод 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. Чи можу я встановити в цьому запиті заголовки?
Віктор Гардубей

4

Знайшли спосіб увімкнути диски без імпорту будь-якої бібліотеки "cors". Він також працює Typescriptі тестує його в хромованій версії 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. Експрес шукав, '/'але у мене не було останньої косої риски функції [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/…
Corey Cole

3

Якщо ви не можете / не можете використовувати плагін cors, виклик setCorsHeaders()функції першим ділом у функції обробника також буде працювати.

Також використовуйте функції respoSuccess / 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:startвказує функції на сервер замість localhost, коли ви використовуєте його у своєму веб-додатку.

Додайте нижче скрипт у html-голові після скрипта init firebase:

 <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 викликав хмарну функцію з неправильним іменем, він мав би викинути помилку 404, а не помилку CORS.

Виправлення імені хмарної функції в моєму додатку Firebase вирішило проблему.

Я заповнив звіт про помилку про це тут https://firebase.google.com/support/troubleshooter/report/bugs

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.