Включение 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 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'});
   })
})

Что я делаю не так? Буду признателен за любую помощь в этом.

ОБНОВИТЬ:

Ответ Дуга Стивенсона помог. Добавление ({происхождение: истинно}) Исправлена проблема, я также имел изменения response.status(500)в response.status(200)который я полностью пропустил в первый.

Андрей Покровский
источник
Также образец в документах здесь
Като
У меня есть некоторые функции, которые работают с предоставленным решением, но сейчас я пробую новую функцию, которая по существу добавляет открытые графики в начало моего index.html и возвращает обновленный index.html, и я не могу заставить его работать :( продолжаю получать КОНТРОЛЬ ДОСТУПА --- ошибка
TheeBen
2
завершение входящего запроса в cors (), как описано выше, было единственным, что сработало для меня
Чарльз Харринг
Вы можете отредактировать свое «обновление», чтобы подчеркнуть, что требуется промежуточное программное обеспечение 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»
отлично подходит
1
Облачные функции Google не позволяют использовать подстановочные знаки: cloud.google.com/functions/docs/writing/…
Кори Коул
73

Вы можете установить CORS в облачной функции следующим образом

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

Нет необходимости импортировать corsпакет

deanwilliammills
источник
2
Это отлично работает для моего случая, облачной функции, которая делает XHR-вызов Mailchimp API.
elverde
1
Это ответ нужен.
Джимми Кейн
1
Облачные функции Google не позволяют использовать подстановочные знаки: cloud.google.com/functions/docs/writing/…
Кори Коул
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/…
Кори Коул
29

Еще одна дополнительная информация, просто для тех, кто через некоторое время погуглил: если вы используете хостинг firebase, вы также можете настроить перезапись, так что, например, URL-адрес (firebase_hosting_host) / api / myfunction перенаправляется на ( firebase_cloudfunctions_host) / функция doStuff. Таким образом, поскольку перенаправление является прозрачным и выполняется на стороне сервера, вам не придется иметь дело с корсами.

Вы можете настроить это с помощью раздела перезаписи в firebase.json:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
Пабло Уркиса
источник
1
imo, это лучший ответ, поскольку он решает реальную проблему без добавления каких-либо дополнительных проблем с безопасностью. Таким образом, облачные функции обслуживаются из того же домена, что и остальные, и вам даже не нужны никакие корсы.
koljaTM 03
3
Это действительно отличная функция, но в настоящее время она работает только в том случае, если функции находятся в регионе по умолчанию (us-central1). Я хотел развернуть свои функции на europe-west1 из-за задержки и столкнулся с этой проблемой: github.com/firebase/firebase-tools/issues/842
Alex Suzuki
Перенаправление работает нормально и делает URL-адрес более чистым, но я не понял, как передать параметры GET. Кажется, что функция (после перезаписи) вызывается без параметров.
royappa
20

Никакие решения CORS у меня не работали ... до сих пор!

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

tl; dr - проверьте журналы функций firebase, если никакие решения CORS не работают, и отладьте любые ошибки, которые у вас есть

tbone849
источник
1
это сводило меня с ума. в моем случае это даже не ошибка кода! это было Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com так, что в основном бесплатная квота была превышена, и функции вернули ошибку
cors
Пару раз здесь, с сервера возвращается та же ошибка, что и cors: Error: internal - это в основном ошибка. Эта ошибка также может произойти, если вы запустите неправильную функцию, например,
неверно введете
Когда вы пытаетесь запросить проверку Google reCAPTCHA в облачной функции, браузер также выдает вам ошибку CORS. Когда я проверяю журнал функций Firebase Console, он говорит access to external network resources not allowed if the billing account is not enabled. После включения биллинговой учетной записи он работает отлично. Это также один из примеров, не связанных с cors, но выдается ошибка cors.
Антонио Оои
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 с установкой заголовков вручную не работали
Джим Фактор
Это работает, но может вызвать ошибку TSlint, если она у вас включена и вы не можете развернуть ее на firebase. Поместите ответ внутрь закрытия корса, чтобы его преодолетьcors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out
1
Здесь 2 ошибки, ребята. Первый. Все, что происходит после функции cors, будет выполняться дважды (поскольку первый запрос является предполетным). Не хорошо. Во-вторых, @SpiralOut в вашем решении приведет к потере регистрации в облачных функциях (очень плохо) и правильной функциональности async / await, вы рискуете преждевременным завершением содержимого функции внутри обратного вызова.
Оливер Диксон
@SpiralOut можно просто отключить цлинт
Влад
1
Узнав много нового о gcf за последний год, я бы больше не рекомендовал этот ответ. Это может быть удобно для быстрых прототипов, но избегайте этого в реальных производственных случаях
Яап Вейланд
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
Сэнди
Это было быстрее и проще всего, спасибо!
Gaurav Kakkar,
8

Я только что опубликовал небольшую статью об этом:

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

Как правило, вы должны использовать пакет Express CORS , который требует небольшого взлома, чтобы соответствовать требованиям в функциях GCF / Firebase.

Надеюсь, это поможет!

mhaligowski
источник
4
Не знаете, что вы имеете в виду под взломом? Хотите немного уточнить? Прочтите ваш пост, но я не вижу, чтобы вы его упоминали
TheeBen
1
автор модуля cors здесь; под "взломом" малиговски просто имел в виду, что ему нужно было обернуть вызов модуля 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, вот суть других предложений:

Chronnie
источник
3
на самом деле, когда я использую функцию onCall в браузере, я получаю ошибку cors. Могу ли я установить в этом запросе заголовки costom?
Виктор Хардубей
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();
});
JerryGoyal
источник
3

Как бы то ни было, при переходе appв onRequest. Я понял, что проблема заключалась в косой черте в конце URL-адреса запроса для функции firebase. Express искал, '/'но у меня не было косой черты в конце функции [project-id].cloudfunctions.net/[function-name]. Ошибка CORS была ложноотрицательной. Когда я добавил косую черту в конце, я получил ожидаемый ответ.

shadyhill
источник
также убедитесь, что вы добавили свой, так [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));
}
KasparTr
источник
2

Если вы тестируете приложение Firebase локально, вам нужно указать функции localhostвместо облака. По умолчанию firebase serveили firebase emulators:startуказывает функции на сервер, а не на localhost, когда вы используете его в своем веб-приложении.

Добавьте ниже скрипт в заголовок html после скрипта инициализации firebase:

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

Обязательно удалите этот фрагмент при развертывании кода на сервере.

JerryGoyal
источник
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*
    });
});
krishnazden
источник
0

В моем случае ошибка была вызвана ограничением доступа к облачной функции. Пожалуйста, добавьте всех пользователей в вызывающий облачные функции. Пожалуйста, поймите ссылку . Пожалуйста, обратитесь к статье для получения дополнительной информации

Kacpero
источник
Пожалуйста, дайте объяснение связанного материала в своем ответе, почему он актуален и тому подобное
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'
});
Агилан I
источник
0

Добавляю свой опыт. Я часами пытался понять, почему у меня возникла ошибка CORS.

Бывает, что я переименовал свою облачную функцию (самое первое, что пробовал после большого обновления).

Поэтому, когда мое приложение firebase вызывало облачную функцию с неправильным именем, оно должно было выдать ошибку 404, а не ошибку CORS.

Исправление имени облачной функции в моем приложении firebase устранило проблему.

Я заполнил отчет об этом здесь https://firebase.google.com/support/troubleshooter/report/bugs

Томас
источник