Mengaktifkan CORS di Fungsi Awan untuk Firebase

141

Saat ini saya sedang belajar cara menggunakan Cloud Functions untuk Firebase dan masalah yang saya alami adalah bahwa saya tidak dapat mengakses fungsi yang saya tulis melalui permintaan AJAX. Saya mendapatkan kesalahan "Tidak Ada 'Akses-Kontrol-Izinkan-Asal'". Berikut ini contoh fungsi yang saya tulis:

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

Fungsi duduk di url ini: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

Firebase docs menyarankan untuk menambahkan CORS middleware di dalam fungsi, saya sudah mencobanya tetapi tidak berfungsi untuk saya: https://firebase.google.com/docs/functions/http-events

Beginilah cara saya melakukannya:

var cors = require('cors');    

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

Apa yang saya lakukan salah? Saya akan menghargai bantuan apa pun dengan ini.

MEMPERBARUI:

Jawaban Doug Stevenson membantu. Menambahkan ({asal: true}) tetap masalah, saya juga harus berubah response.status(500)untuk response.status(200)yang saya benar-benar ketinggalan pada awalnya.

Andrey Pokrovskiy
sumber
Juga contoh dalam dokumen di sini
Kato
Saya memiliki beberapa fungsi yang berfungsi dengan solusi yang disediakan tetapi sekarang saya sedang mencoba fungsi baru yang pada dasarnya menambahkan grafik terbuka ke bagian atas index.html saya dan mengembalikan index.html yang diperbarui dan saya tidak dapat membuatnya berfungsi :( terus dapatkan ACCESS-CONTROL --- error
TheeBen
2
membungkus permintaan masuk dalam kor () seperti di atas adalah satu-satunya hal yang berhasil untuk saya
Charles Harring
dapatkah Anda mengedit "pembaruan" Anda untuk menegaskan bahwa cork middleware diperlukan? Ini akan menghemat waktu beberapa orang
Antoine Weber

Jawaban:

151

Ada dua fungsi sampel yang disediakan oleh tim Firebase yang menunjukkan penggunaan CORS:

Sampel kedua menggunakan cara kerja yang berbeda dengan kor daripada yang Anda gunakan saat ini.

Juga, pertimbangkan mengimpor seperti ini, seperti yang ditunjukkan dalam sampel:

const cors = require('cors')({origin: true});
Doug Stevenson
sumber
2
Terima kasih! Menambahkan ({origin: true}) membantu.
Andrey Pokrovskiy
2
Bagus, Anda pasti perlu origin: truemeninggalkannya karena ini tidak akan berhasil
Scott
4
Sepertinya ini adalah tempat daftar putih domain untuk mengizinkan akses didefinisikan? Dan pengaturan origin: truememungkinkan setiap domain untuk mengakses? ( npmjs.com/package/cors ) @ Patrick Stevenson Apakah Anda pikir firebase dapat menulis dokumen tentang dasar-dasar yang diperlukan untuk fungsi https klien / server? Repo sampel bagus, tetapi kami telah melewatkan sedikit kebutuhan tambahan ini.
Alan
9
Bagi siapa pun yang ingin menambahkan dukungan CORS ke back-end mereka: pastikan Anda memahami konsekuensi dan cara mengkonfigurasinya dengan benar. "origin: true" keren untuk pengujian tetapi mengalahkan seluruh tujuan :)
dSebastien
1
fungsi Google cloud tidak mengizinkan asal wildcard: cloud.google.com/functions/docs/writing/…
Corey Cole
73

Anda dapat mengatur CORS dalam fungsi cloud seperti ini

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

Tidak perlu mengimpor corspaket

deanwilliammills
sumber
2
Ini berfungsi dengan baik untuk kasus saya, fungsi cloud yang membuat panggilan XHR ke Mailchimp API.
Elverde
1
Itulah jawaban yang dibutuhkan.
Jimmy Kane
1
fungsi Google cloud tidak mengizinkan asal wildcard: cloud.google.com/functions/docs/writing/…
Corey Cole
4
@CoreyCole Saya pikir itu hanya jika Anda perlu menambahkan Authorizationheader. Di atas tampaknya berfungsi ok.
Stuart Memo
Di mana harus menempatkan baris kode ini? Bagian mana dari fungsi cloud?
Antonio Ooi
41

Bagi siapa pun yang mencoba melakukan ini dalam naskah, ini adalah kode:

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
sumber
3
Solusi akan membuat Anda kehilangan logging pada fungsi cloud (sangat buruk) dan fungsionalitas async / menunggu yang tepat, Anda berisiko konten fungsi yang diakhiri sebelum waktunya di dalam panggilan balik pada panggilan lama.
Oliver Dixon
2
fungsi Google cloud tidak mengizinkan asal wildcard: cloud.google.com/functions/docs/writing/…
Corey Cole
29

Satu info tambahan, hanya demi orang-orang yang googling ini setelah beberapa waktu: Jika Anda menggunakan hosting berbasis web, Anda juga dapat mengatur penulisan ulang, sehingga misalnya url seperti (firebase_hosting_host) / api / myfunction redirect ke ( firebase_cloudfunctions_host) / fungsi doStuff. Dengan begitu, karena pengalihan transparan dan sisi-server, Anda tidak harus berurusan dengan cors.

Anda dapat mengaturnya dengan bagian penulisan ulang di firebase.json:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
Pablo Urquiza
sumber
1
imo, ini adalah jawaban terbaik, karena ini memecahkan masalah yang sebenarnya tanpa menambahkan masalah keamanan tambahan. Dengan cara ini fungsi cloud dilayani dari domain yang sama dengan yang lainnya dan Anda bahkan tidak memerlukan kor.
koljaTM
3
Ini memang fitur hebat, tetapi saat ini hanya berfungsi jika fungsinya hidup di wilayah default (us-central1). Saya ingin menyebarkan fungsi saya ke eropa-barat1 untuk alasan latensi dan mengalami masalah ini: github.com/firebase/firebase-tools/issues/842
Alex Suzuki
Pengalihan berfungsi dengan baik dan membuat URL lebih bersih, tetapi saya belum menemukan cara untuk melewatkan parameter GET. Fungsi (setelah menulis ulang) tampaknya dipanggil tanpa parameter.
royappa
20

Tidak ada solusi CORS yang bekerja untuk saya ... sampai sekarang!

Tidak yakin apakah ada orang lain yang mengalami masalah yang sama dengan saya, tetapi saya mengatur CORS seperti 5 cara berbeda dari contoh yang saya temukan dan sepertinya tidak ada yang berhasil. Saya membuat contoh minimal dengan Plunker untuk melihat apakah itu benar-benar bug, tetapi contohnya berjalan dengan indah. Saya memutuskan untuk memeriksa log fungsi firebase (ditemukan di konsol firebase) untuk melihat apakah itu dapat memberi tahu saya apa pun. Saya memiliki beberapa kesalahan dalam kode server node saya , tidak terkait dengan CORS , bahwa ketika saya debug membebaskan saya dari pesan kesalahan CORS saya . Saya tidak tahu mengapa kesalahan kode yang tidak terkait dengan CORS mengembalikan respons kesalahan CORS, tetapi hal itu membuat saya jatuh ke lubang kelinci yang salah selama beberapa jam ...

tl; dr - periksa log fungsi firebase Anda jika tidak ada solusi CORS yang berfungsi dan debug setiap kesalahan yang Anda miliki

tbone849
sumber
1
ini membuatku gila. dalam kasus saya itu bahkan bukan kesalahan dalam kode! itu Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com pada dasarnya kuota gratis terlampaui dan fungsi mengembalikan kesalahan kor
Stanislau Buzunko
Terjadi beberapa kali di sini, kesalahan yang sama dikembalikan dari server dan juga kors: Kesalahan: internal pada dasarnya adalah kesalahan. Kesalahan ini juga akan terjadi jika Anda menjalankan fungsi yang salah, misalnya salah ketik nama fungsi
Henrik Bøgelund Lavstsen
Ketika Anda mencoba untuk meminta verifikasi Google reCAPTCHA dalam fungsi cloud, browser juga melempar Anda kesalahan CORS. Ketika saya memeriksa log fungsi Firebase Console, katanya access to external network resources not allowed if the billing account is not enabled. Setelah mengaktifkan akun penagihan, itu berfungsi dengan baik. Ini juga merupakan salah satu contoh non-kor terkait tetapi kesalahan korsel dilemparkan.
Antonio Ooi
19

Saya punya sedikit tambahan untuk @Andreys menjawab pertanyaannya sendiri.

Tampaknya Anda tidak perlu memanggil fungsi panggil balik dalam cors(req, res, cb)fungsi, jadi Anda bisa memanggil modul kors di bagian atas fungsi Anda, tanpa menyematkan semua kode Anda dalam panggilan balik. Ini jauh lebih cepat jika Anda ingin menerapkan kor setelahnya.

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

Jangan lupa untuk inor kors seperti yang disebutkan dalam posting pembukaan:

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

Jaap Weijland
sumber
1
ini bekerja ketika SO lainnya menjawab dengan menetapkan tajuk secara manual tidak
Jim Factor
Ini berfungsi tetapi ini dapat menyebabkan kesalahan TSlint jika Anda telah mengaktifkannya dan Anda tidak dapat menggunakan ke firebase. Letakkan respons di dalam penutupan kor untuk mengatasinyacors(request, response, () => { return response.send("Hello from Firebase!"); });
Spiral Out
1
2 kesalahan di sini kawan. Pertama. Apa pun setelah fungsi kors akan berjalan dua kali (karena permintaan pertama adalah preflight). Tidak baik. Kedua, @SpiralOut solusi Anda akan membuat Anda kehilangan logging pada fungsi cloud (sangat buruk) dan fungsionalitas async / menunggu yang tepat, Anda berisiko konten fungsi yang diakhiri secara prematur di dalam callback.
Oliver Dixon
@SpiralOut Anda cukup menonaktifkan tslint
Vlad
1
Setelah belajar banyak tentang gcf pada tahun lalu, saya tidak akan merekomendasikan jawaban ini lagi. Ini bisa berguna untuk prototipe cepat, tetapi hindari ini dalam kasus produksi nyata
Jaap Weijland
11

Ini mungkin bermanfaat. Saya membuat fungsi cloud HTTP firebase dengan express (URL khusus)

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

Pastikan Anda menambahkan bagian menulis ulang

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]
Sandy
sumber
1
Jawabanmu terlalu rendah temanku, jawaban terbaik sejauh ini.
Avram Virgil
Terima kasih. @ AvramVirgil
Sandy
Ini tercepat dan termudah dari semuanya, Terima kasih!
Gaurav Kakkar
8

Saya baru saja menerbitkan sedikit tentang itu:

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

Secara umum, Anda harus menggunakan paket Express CORS , yang memerlukan sedikit peretasan untuk memenuhi persyaratan dalam Fungsi GCF / Firebase.

Semoga itu bisa membantu!

mhaligowski
sumber
4
Tidak yakin apa yang Anda maksud dengan peretasan? Mau sedikit menguraikan? Baca posting Anda tetapi saya tidak melihat Anda menyebutkannya
TheeBen
1
penulis modul kor di sini; oleh "hacking" mhaligowski berarti dia harus membungkus panggilan ke modul cors agar sesuai dengan cara Express memanggil middleware (mis., menyediakan fungsi sebagai parameter ketiga setelah req & res)
Troy
4

Jika ada orang seperti saya di luar sana: Jika Anda ingin memanggil fungsi cloud dari proyek yang sama dengan fungsi cloud itu sendiri, Anda dapat init firebase sdk dan gunakan metode onCall. Ini akan menangani segalanya untuk Anda:

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

Sebut fungsi ini seperti ini:

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

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

Jika Anda tidak dapat menginisialisasi SDK di sini adalah esensi dari saran lain:

Chronnie
sumber
3
sebenarnya ketika saya menggunakan onCall func pada browser saya mendapat error cors. Bisakah saya menetapkan header costom dalam permintaan ini?
Viktor Hardubej
4

Menemukan cara untuk mengaktifkan kor tanpa mengimpor perpustakaan 'kor'. Ini juga berfungsi dengan Typescriptdan mengujinya di chrome versi 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
sumber
3

Untuk apa layak itu aku sedang mengalami masalah yang sama ketika melewati appke dalam onRequest. Saya menyadari bahwa masalahnya adalah garis miring pada url permintaan untuk fungsi firebase. Express sedang mencari '/'tetapi saya tidak memiliki garis miring pada fungsi [project-id].cloudfunctions.net/[function-name]. Kesalahan CORS adalah negatif palsu. Ketika saya menambahkan garis miring, saya mendapat respons yang saya harapkan.

teduh
sumber
juga pastikan Anda menambahkan Anda [project-id]karena ini adalah masalah yang saya hadapi
dicabut
3

Hanya cara ini yang berfungsi untuk saya karena saya memiliki otorisasi dalam permintaan saya:

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
sumber
fungsi Google cloud tidak mengizinkan asal wildcard: cloud.google.com/functions/docs/writing/…
Corey Cole
3

Jika Anda tidak / tidak bisa menggunakan plugin cors, panggil setCorsHeaders() fungsi hal pertama dalam fungsi handler juga akan berfungsi.

Juga gunakan fungsi respondSuccess / Error saat membalas kembali.

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
sumber
2

Jika Anda menguji aplikasi firebase secara lokal, maka Anda perlu mengarahkan fungsi ke localhostbukan cloud. Secara default, firebase serveatau firebase emulators:startarahkan fungsi ke server alih-alih localhost saat Anda menggunakannya di aplikasi web Anda.

Tambahkan skrip di bawah dalam kepala html setelah skrip firebase init:

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

Pastikan untuk menghapus cuplikan ini saat menggunakan kode ke server.

JerryGoyal
sumber
2

Mengubah truedengan "*"melakukan trik untuk saya, jadi seperti ini tampilannya:

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

Saya mencoba pendekatan ini karena secara umum, ini adalah bagaimana header respons ini diatur:

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

Ketahuilah bahwa ini akan memungkinkan domain apa pun untuk memanggil titik akhir Anda karena itu TIDAK aman.

Selain itu, Anda dapat membaca lebih lanjut di dokumen: https://github.com/expressjs/cors

rampok
sumber
1

Jika Anda tidak menggunakan Express atau hanya ingin menggunakan CORS. Kode berikut akan membantu menyelesaikannya

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

Dalam kasus saya kesalahan itu disebabkan oleh akses batas fungsi cloud invoker. Silakan tambahkan semua Pengguna ke penyerang fungsi cloud. Harap tautkan tautan . Silakan merujuk ke artikel untuk info lebih lanjut

Kacpero
sumber
Harap berikan beberapa penjelasan tentang materi terkait dalam jawaban Anda, mengapa itu relevan dan semacamnya
Firefly
0

Jika tidak ada solusi lain yang berfungsi, Anda dapat mencoba menambahkan alamat di bawah ini di awal panggilan untuk mengaktifkan CORS - redirect:

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

Kode sampel dengan permintaan JQuery AJAX:

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

Menambahkan pengalaman saya. Saya menghabiskan waktu berjam-jam untuk menemukan mengapa saya memiliki kesalahan CORS.

Kebetulan saya mengganti nama fungsi cloud saya (yang pertama saya coba setelah upgrade besar).

Jadi, ketika aplikasi firebase saya memanggil fungsi cloud dengan nama yang salah, seharusnya dilempar kesalahan 404, bukan kesalahan CORS.

Memperbaiki nama fungsi cloud di aplikasi firebase saya memperbaiki masalah ini.

Saya telah mengisi laporan bug tentang ini di sini https://firebase.google.com/support/troubleshooter/report/bugs

Thomas
sumber