Dapatkan URL Download dari file yang diupload dengan Cloud Functions for Firebase

125

Setelah mengupload file di Firebase Storage dengan Functions for Firebase, saya ingin mendapatkan url download dari file tersebut.

Aku punya ini :

...

return bucket
    .upload(fromFilePath, {destination: toFilePath})
    .then((err, file) => {

        // Get the download url of file

    });

File objek memiliki banyak parameter. Bahkan satu nama mediaLink. Namun, jika saya mencoba mengakses tautan ini, saya mendapatkan kesalahan ini:

Pengguna anonim tidak memiliki storage.objects. dapatkan akses ke objek ...

Adakah yang bisa memberi tahu saya cara mendapatkan Url unduhan publik?

Terima kasih

Valentin
sumber
Lihat juga posting ini yang merekonstruksi URL dari data yang tersedia di fungsi tersebut.
Kato

Jawaban:

134

Anda harus membuat URL yang ditandatangani menggunakan getSignedURL melalui modul NPM @ google-cloud / storage .

Contoh:

const gcs = require('@google-cloud/storage')({keyFilename: 'service-account.json'});
// ...
const bucket = gcs.bucket(bucket);
const file = bucket.file(fileName);
return file.getSignedUrl({
  action: 'read',
  expires: '03-09-2491'
}).then(signedUrls => {
  // signedUrls[0] contains the file's public URL
});

Anda harus menginisialisasi @google-cloud/storagedengan kredensial akun layanan Anda karena kredensial default aplikasi tidak akan cukup.

UPDATE : Cloud Storage SDK sekarang dapat diakses melalui Firebase Admin SDK, yang bertindak sebagai pembungkus di sekitar @ google-cloud / storage. Satu-satunya cara adalah jika Anda:

  1. Masukkan SDK dengan akun layanan khusus, biasanya melalui instance non-default kedua.
  2. Atau, tanpa akun layanan, dengan memberi akun layanan App Engine default izin "signBlob".
James Daniels
sumber
74
Ini aneh. Kita bisa dengan mudah mendapatkan Url Download dari referensi Storage saat menggunakan Firebase Android, iOS dan Web SDK. Kenapa tidak semudah di admin? NB: Di mana saya dapat menemukan 'service-account.json' yang diperlukan untuk menginisialisasi gcs?
Valentin
2
Ini karena admin-sdk tidak memiliki tambahan Cloud Storage. Anda bisa mendapatkan akun layanan admin-sdk json di sini console.firebase.google.com/project/_/settings/serviceaccounts/…
James Daniels
18
URL yang dibuat dengan metode ini sangat panjang. URL yang dihasilkan oleh metode yang diusulkan @martemorfosis jauh lebih baik. Apakah ada fungsi yang menghasilkan URL itu? Itulah yang saya simpan di database untuk digunakan di masa mendatang saat saya menggunakan firebase-sdk. Metode mirror harus ada di domain Functions.
Bogac
3
Bagaimana kita bisa mengunggah service-account.json bersama dengan fungsi yang diterapkan? Saya telah mencoba menempatkannya di folder fungsi dan mereferensikannya di bidang file di package.json tetapi tidak diterapkan. Terima kasih.
David Aroesti
2
Apakah kita diharuskan menambah actiondan expires?
Chad Bingham
83

Berikut adalah contoh tentang cara menentukan token unduhan saat mengunggah:

const UUID = require("uuid-v4");

const fbId = "<YOUR APP ID>";
const fbKeyFile = "./YOUR_AUTH_FIlE.json";
const gcs = require('@google-cloud/storage')({keyFilename: fbKeyFile});
const bucket = gcs.bucket(`${fbId}.appspot.com`);

var upload = (localFile, remoteFile) => {

  let uuid = UUID();

  return bucket.upload(localFile, {
        destination: remoteFile,
        uploadType: "media",
        metadata: {
          contentType: 'image/png',
          metadata: {
            firebaseStorageDownloadTokens: uuid
          }
        }
      })
      .then((data) => {

          let file = data[0];

          return Promise.resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent(file.name) + "?alt=media&token=" + uuid);
      });
}

lalu telepon dengan

upload(localPath, remotePath).then( downloadURL => {
    console.log(downloadURL);
  });

Kuncinya di sini adalah ada metadataobjek yang bersarang di dalam metadataproperti opsi. Menyetel firebaseStorageDownloadTokenske nilai uuid-v4 akan memberi tahu Cloud Storage untuk menggunakannya sebagai token autentikasi publiknya.

Terima kasih banyak kepada @martemorfosis

Drew Beaupre
sumber
Bagaimana cara mendapatkan token UUID yang valid untuk file yang sudah diupload di Storage? Membuat UUID acak tidak membantu. Ada petunjuk?
DerFaizio
3
Temukan jawabannya di postingan @martemorfosis. UUID bisa diambil dari object.metadata exports.uploadProfilePic = functions.storage.object (). OnChange (event => {const object = event.data; // Objek Storage. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio
Terima kasih atas contoh embernya! Saya mencoba kombinasi yang berbeda untuk metode ember dan file selama hampir 1 jam :)
JCarlosR
1
Terima kasih atas jawaban anda! Dalam kasus saya, saya mengupload dengan bucket.file (fileName) .createWriteStream yang tidak mengembalikan data saat selesai mengupload, sebagai hasilnya, saya menggunakan encodeURIComponent (fileName) dan bukan encodeURIComponent (file.name).
Stanislau Buzunko
2
Ini harus menjadi jawaban yang benar. Ini menghasilkan URL yang mirip dengan yang dihasilkan oleh SDK Firebase (@DevMike), dan saya yakin itulah yang mereka lakukan di balik layar.
Samuel E.
64

Jawaban ini akan merangkum opsi untuk mendapatkan URL download saat mengupload file ke Google / Firebase Cloud Storage. Ada tiga jenis URL unduhan:

  1. URL unduhan yang ditandatangani, yang bersifat sementara dan memiliki fitur keamanan
  2. URL unduhan token, yang persisten dan memiliki fitur keamanan
  3. URL unduhan publik, yang persisten dan kurang keamanan

Ada tiga cara untuk mendapatkan URL unduhan token. Dua URL unduhan lainnya hanya memiliki satu cara untuk mendapatkannya.

Dari Konsol Penyimpanan Firebase

Anda bisa mendapatkan URL download dari Firebase Storage console:

masukkan deskripsi gambar di sini

URL unduhan terlihat seperti ini:

https://firebasestorage.googleapis.com/v0/b/languagetwo-cd94d.appspot.com/o/Audio%2FEnglish%2FUnited_States-OED-0%2Fabout.mp3?alt=media&token=489c48b3-23fb-4270-bd85-0a328d2808e5

Bagian pertama adalah jalur standar ke file Anda. Pada akhirnya adalah tanda. URL unduhan ini bersifat permanen, yaitu tidak akan kedaluwarsa, meskipun Anda dapat mencabutnya.

getDownloadURL () Dari Front End

The dokumentasi memberitahu kita untuk menggunakan getDownloadURL():

let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();

Ini mendapatkan URL unduhan yang sama yang bisa Anda dapatkan dari konsol Firebase Storage. Metode ini mudah tetapi mengharuskan Anda mengetahui jalur ke file Anda, yang dalam aplikasi saya berisi sekitar 300 baris kode, untuk struktur database yang relatif sederhana. Jika database Anda rumit, ini akan menjadi mimpi buruk. Dan Anda dapat mengunggah file dari ujung depan, tetapi ini akan mengekspos kredensial Anda kepada siapa pun yang mengunduh aplikasi Anda. Jadi untuk sebagian besar proyek, Anda pasti ingin mengunggah file Anda dari Node back end atau Google Cloud Functions, lalu dapatkan URL unduhan dan simpan ke database Anda bersama dengan data lain tentang file Anda.

getSignedUrl () untuk URL Unduhan Sementara

getSignedUrl () mudah digunakan dari back end Node atau Google Cloud Functions:

  function oedPromise() {
    return new Promise(function(resolve, reject) {
      http.get(oedAudioURL, function(response) {
        response.pipe(file.createWriteStream(options))
        .on('error', function(error) {
          console.error(error);
          reject(error);
        })
        .on('finish', function() {
          file.getSignedUrl(config, function(err, url) {
            if (err) {
              console.error(err);
              return;
            } else {
              resolve(url);
            }
          });
        });
      });
    });
  }

URL unduhan yang ditandatangani terlihat seperti ini:

https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio%2FSpanish%2FLatin_America-Sofia-Female-IBM%2Faqu%C3%AD.mp3?GoogleAccessId=languagetwo-cd94d%40appspot.gserviceaccount.com&Expires=4711305600&Signature=WUmABCZIlUp6eg7dKaBFycuO%2Baz5vOGTl29Je%2BNpselq8JSl7%2BIGG1LnCl0AlrHpxVZLxhk0iiqIejj4Qa6pSMx%2FhuBfZLT2Z%2FQhIzEAoyiZFn8xy%2FrhtymjDcpbDKGZYjmWNONFezMgYekNYHi05EPMoHtiUDsP47xHm3XwW9BcbuW6DaWh2UKrCxERy6cJTJ01H9NK1wCUZSMT0%2BUeNpwTvbRwc4aIqSD3UbXSMQlFMxxWbPvf%2B8Q0nEcaAB1qMKwNhw1ofAxSSaJvUdXeLFNVxsjm2V9HX4Y7OIuWwAxtGedLhgSleOP4ErByvGQCZsoO4nljjF97veil62ilaQ%3D%3D

URL yang ditandatangani memiliki tanggal kedaluwarsa dan tanda tangan yang panjang. Dokumentasi untuk baris perintah gsutil signurl -d mengatakan bahwa URL bertanda tangan bersifat sementara: masa berlaku default adalah satu jam dan masa berakhir maksimum adalah tujuh hari.

Saya akan mengomel di sini bahwa getSignedUrl tidak pernah mengatakan bahwa URL Anda yang ditandatangani akan kedaluwarsa dalam seminggu. Kode dokumentasi memiliki 3-17-2025tanggal kedaluwarsa, yang menyarankan agar Anda dapat mengatur tahun kedaluwarsa di masa mendatang. Aplikasi saya bekerja dengan sempurna, lalu mogok seminggu kemudian. Pesan kesalahan mengatakan bahwa tanda tangan tidak cocok, bukan bahwa URL unduhan telah kedaluwarsa. Saya membuat berbagai perubahan pada kode saya, dan semuanya bekerja ... sampai semuanya macet seminggu kemudian. Ini berlangsung selama lebih dari sebulan karena frustrasi.

Buat File Anda Tersedia untuk Publik

Anda dapat mengatur izin pada file Anda untuk dibaca publik, seperti yang dijelaskan dalam dokumentasi . Ini dapat dilakukan dari Cloud Storage Browser atau dari server Node Anda. Anda dapat membuat satu file menjadi publik atau direktori atau seluruh database Storage Anda. Inilah kode Node:

var webmPromise = new Promise(function(resolve, reject) {
      var options = {
        destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
        predefinedAcl: 'publicRead',
        contentType: 'audio/' + audioType,
      };

      synthesizeParams.accept = 'audio/webm';
      var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
      textToSpeech.synthesize(synthesizeParams)
      .then(function(audio) {
        audio.pipe(file.createWriteStream(options));
      })
      .then(function() {
        console.log("webm audio file written.");
        resolve();
      })
      .catch(error => console.error(error));
    });

Hasilnya akan terlihat seperti ini di Cloud Storage Browser Anda:

masukkan deskripsi gambar di sini

Siapa pun kemudian dapat menggunakan jalur standar untuk mengunduh file Anda:

https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3

Cara lain untuk membuat file menjadi publik adalah dengan menggunakan metode makePublic () . Saya belum bisa membuatnya berfungsi, sulit untuk mendapatkan bucket dan jalur file yang benar.

Alternatif yang menarik adalah dengan menggunakan Daftar Kontrol Akses . Anda dapat membuat file tersedia hanya untuk pengguna yang Anda masukkan ke dalam daftar, atau gunakan authenticatedReaduntuk membuat file tersedia bagi siapa saja yang masuk dari akun Google. Jika ada opsi "siapa saja yang login ke aplikasi saya menggunakan Firebase Auth", saya akan menggunakan ini, karena akan membatasi akses hanya untuk pengguna saya.

Buat URL Download Anda Sendiri dengan firebaseStorageDownloadTokens

Beberapa jawaban mendeskripsikan properti objek Google Storage yang tidak terdokumentasi firebaseStorageDownloadTokens. Dengan ini, Anda dapat memberi tahu Storage, token yang ingin Anda gunakan. Anda dapat membuat token dengan uuidmodul Node. Empat baris kode dan Anda dapat membuat URL unduhan Anda sendiri, URL unduhan yang sama yang Anda dapatkan dari konsol atau getDownloadURL(). Empat baris kode tersebut adalah:

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }
https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);

Berikut kode dalam konteks:

var webmPromise = new Promise(function(resolve, reject) {
  var options = {
    destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
    contentType: 'audio/' + audioType,
    metadata: {
      metadata: {
        firebaseStorageDownloadTokens: uuid,
      }
    }
  };

      synthesizeParams.accept = 'audio/webm';
      var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
      textToSpeech.synthesize(synthesizeParams)
      .then(function(audio) {
        audio.pipe(file.createWriteStream(options));
      })
      .then(function() {
        resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);
      })
      .catch(error => console.error(error));
});

Itu bukan kesalahan ketik - Anda harus membuat firebaseStorageDownloadTokenslapisan ganda metadata:!

Doug Stevenson menunjukkan bahwa firebaseStorageDownloadTokensitu bukan fitur Google Cloud Storage resmi. Anda tidak akan menemukannya di dokumentasi Google mana pun, dan tidak ada janji akan menemukannya di versi mendatang @google-cloud. Saya suka firebaseStorageDownloadTokenskarena itu satu-satunya cara untuk mendapatkan apa yang saya inginkan, tetapi memiliki "bau" yang tidak aman digunakan.

Mengapa Tidak Ada getDownloadURL () dari Node?

Seperti yang ditulis @Clinton, Google harus membuat file.getDownloadURL()metode di @google-cloud/storage(yaitu, ujung belakang Node Anda). Saya ingin mengupload file dari Google Cloud Functions dan mendapatkan URL download token.

Thomas David Kehoe
sumber
10
Saya membuat masalah tentang @google-cloud/storagehal ini, silakan beri
Juara
1
tautan makePublic () terbaru .
galki
1
Sepertinya firebaseStorageDownloadTokenstidak berfungsi lagi.
Mason
1
Jawaban yang diterima menunjukkan bahwa tidak mungkin mendapatkan url unduhan persisten yang tidak kedaluwarsa yang tidak benar. Rincian di sini dalam jawaban Anda sangat bagus dan harus ditandai sebagai jawaban yang benar. Terima kasih.
DevMike
2
@ Thomas terima kasih atas ringkasannya yang luar biasa! Anda menyebutkan bahwa ada 3 cara untuk mendapatkan URL unduhan token yang persisten tetapi Anda hanya membagikan 2 cara: (a) Dari Konsol Penyimpanan Firebase, dan (b) getDownloadURL () Dari Bagian Depan. Saya ingin tahu apa cara ke-3?
czphilip
23

Dengan perubahan terbaru dalam respons objek fungsi, Anda bisa mendapatkan semua yang Anda butuhkan untuk "menyatukan" URL unduhan seperti:

 const img_url = 'https://firebasestorage.googleapis.com/v0/b/[YOUR BUCKET]/o/'
+ encodeURIComponent(object.name)
+ '?alt=media&token='
+ object.metadata.firebaseStorageDownloadTokens;

console.log('URL',img_url);
Demian S
sumber
2
Apakah Anda mengacu pada tanggapan objek dari bucket.file().upload()? Saya tidak menerima properti metadata apa pun dalam data respons, dan saya tidak yakin bagaimana mendapatkannya firebaseStorageDownloadTokens.
Dygerati
juga [BUCKET ANDA] adalah bucket.name, Anda tidak perlu melakukan hardcode atau menggunakan var lokal tambahan
Călin Darie
4
Masalah dengan solusi ini adalah URL layanan di-hardcode. Jika Firebase / Google mengubahnya, itu mungkin rusak. Menggunakan metadata.mediaLinkproperti mencegah masalah seperti itu.
Laurent
2
Tidak mendukung kasus untuk membangun URL seperti ini. Ini mungkin berhasil hari ini, tetapi bisa rusak di masa depan. Anda sebaiknya hanya menggunakan API yang disediakan untuk menghasilkan URL unduhan yang tepat.
Doug Stevenson
1
Mengandalkan URL hardcode yang mungkin berubah adalah pilihan yang buruk.
Laurent
23

Jika Anda sedang mengerjakan proyek Firebase, Anda dapat membuat URL yang ditandatangani di Cloud Function tanpa menyertakan pustaka lain atau mengunduh file kredensial. Anda hanya perlu mengaktifkan IAM API dan menambahkan peran ke akun layanan Anda yang ada (lihat di bawah).

Inisialisasi perpustakaan admin dan dapatkan referensi file seperti yang biasa Anda lakukan:

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

admin.initializeApp(functions.config().firebase)

const myFile = admin.storage().bucket().file('path/to/my/file')

Anda kemudian membuat URL yang ditandatangani dengan

myFile.getSignedUrl({action: 'read', expires: someDateObj}).then(urls => {
    const signedUrl = urls[0]
})

Pastikan akun layanan Firebase Anda memiliki izin yang memadai untuk menjalankan ini

  1. Buka konsol Google API dan aktifkan IAM API ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )
  2. Masih di konsol API, buka menu utama, "IAM & admin" -> "IAM"
  3. Klik edit untuk peran "akun layanan default App Engine"
  4. Klik "Tambahkan peran lain", dan tambahkan peran yang disebut "Pembuat Token Akun Layanan"
  5. Simpan dan tunggu sebentar agar perubahan menyebar

Dengan konfigurasi Firebase vanilla, pertama kali Anda menjalankan kode di atas, Anda akan mendapatkan kesalahan Identity and Access Management (IAM) API belum pernah digunakan dalam proyek XXXXXX sebelumnya atau dinonaktifkan. . Jika Anda mengikuti tautan dalam pesan kesalahan dan mengaktifkan IAM API, Anda akan mendapatkan kesalahan lain: Izin iam.serviceAccounts.signBlob diperlukan untuk melakukan operasi ini pada akun layanan my-service-account . Menambahkan peran Token Creator memperbaiki masalah izin kedua ini.

SMX
sumber
Saya baru saja akan meninggalkan jawaban dengan pada dasarnya detail yang sama yang AKHIRNYA saya pahami dengan cara yang sulit - semoga saja saya telah membaca solusi sejauh ini sebelumnya: / Ini berhasil untuk saya pada 12/12/18. Terima kasih untuk instruksi rinci, sangat membantu kami pemula !!
Kat
2
Signedurl saya kedaluwarsa dalam 2 minggu tetapi saya menggunakan admin.initializeApp () tanpa kunci, apakah ini masalahnya? Saya memiliki akun layanan default aplikasi App Engine yang disetel ke "pemilik" dan Agen Layanan Cloud Functions, saya baru saja menghapus "pemilik" untuk saat ini dan menambahkan "Pembuat Token Akun Layanan"
Amit Bravo
2
URL yang ditandatangani kedaluwarsa dalam 7 hari. Anda dapat menyetel tanggal kedaluwarsa yang lebih pendek tetapi tidak lebih lama.
Thomas David Kehoe
Bagaimana cara menyegarkan url jika kedaluwarsa?
Manoj MM
bagaimana cara menyegarkan url untuk mengaturnya ke waktu yang lebih lama?
Saifallak
17

Salah satu metode yang saya gunakan dengan sukses adalah dengan menetapkan nilai UUID v4 ke kunci yang dinamai firebaseStorageDownloadTokensdalam metadata file setelah selesai mengupload dan kemudian menyusun sendiri URL download mengikuti struktur yang digunakan Firebase untuk menghasilkan URL ini, misalnya:

https://firebasestorage.googleapis.com/v0/b/[BUCKET_NAME]/o/[FILE_PATH]?alt=media&token=[THE_TOKEN_YOU_CREATED]

Saya tidak tahu seberapa "aman" menggunakan metode ini (mengingat Firebase dapat mengubah cara menghasilkan URL unduhan di masa mendatang) tetapi mudah untuk diterapkan.

martemorfosis
sumber
1
Apakah Anda memiliki contoh di mana Anda menetapkan nilai uuid?
Drew Beaupre
1
Saya memiliki pertanyaan yang sama dengan Drew, di mana Anda menyetel metadata? Saya mencoba untuk mengatur sementara fungsi bucket.upload tidak berfungsi.
Vysakh Sreenivasan
1
Vysakh, saya telah memposting jawaban lengkap dengan contoh. Semoga membantu Anda.
Drew Beaupre
Di mana / bagaimana Anda membuat token?
CodyBugstein
3
Saya tidak akan menganggap teknik ini "aman", karena URL unduhan dimaksudkan untuk menjadi buram, yang komponennya tidak boleh dipecah atau dirakit.
Doug Stevenson
16

Bagi mereka yang bertanya-tanya ke mana file Firebase Admin SDK serviceAccountKey.json harus disimpan. Letakkan saja di folder fungsi dan terapkan seperti biasa.

Saya masih bingung mengapa kita tidak bisa begitu saja mendapatkan url unduhan dari metadata seperti yang kita lakukan di Javascript SDK. Membuat url yang pada akhirnya akan kedaluwarsa dan menyimpannya dalam database tidak diinginkan.

Clinton
sumber
15

Saya sarankan menggunakan opsi predefinedAcl: 'publicRead'saat mengupload file dengan Cloud Storage NodeJS 1.6.x atau +:

const options = {
    destination: yourFileDestination,
    predefinedAcl: 'publicRead'
};

bucket.upload(attachment, options);

Kemudian, mendapatkan URL publik itu semudah:

bucket.upload(attachment, options).then(result => {
    const file = result[0];
    return file.getMetadata();
}).then(results => {
    const metadata = results[0];
    console.log('metadata=', metadata.mediaLink);
}).catch(error => {
    console.error(error);
});
Laurent
sumber
2
Itu sebenarnya tampak berhasil. Satu-satunya downside yang saya lihat sejauh ini adalah bahwa jika Anda menekan gambar di bilah URL browser, itu akan mengunduh gambar daripada melihatnya sebaris.
Michael Giovanni Pumo
file.getMetadata () melakukan trik untuk saya setelah menggunakan metode save () pada referensi file. Menggunakannya di NodeJS dengan firebase-admin sdk.
Pascal Lamers
tidak berfungsi, saya mendapatkan penelepon Anonim tidak memiliki storage.objects.get akses ke your_app / image.jpg
Manoj MM
9

Maaf tetapi saya tidak dapat mengirim komentar untuk pertanyaan Anda di atas karena reputasi yang hilang, jadi saya akan memasukkannya dalam jawaban ini.

Lakukan seperti yang dinyatakan di atas dengan membuat Url yang ditandatangani, tetapi alih-alih menggunakan service-account.json, saya pikir Anda harus menggunakan serviceAccountKey.json yang dapat Anda hasilkan di (ganti PROJECTID ANDA sesuai)

https://console.firebase.google.com/project/YOURPROJECTID/settings/serviceaccounts/adminsdk

Contoh:

const gcs = require('@google-cloud/storage')({keyFilename: 'serviceAccountKey.json'});
// ...
const bucket = gcs.bucket(bucket);
// ...
return bucket.upload(tempLocalFile, {
        destination: filePath,
        metadata: {
          contentType: 'image/jpeg'
        }
      })
      .then((data) => {
        let file = data[0]
        file.getSignedUrl({
          action: 'read',
          expires: '03-17-2025'
        }, function(err, url) {
          if (err) {
            console.error(err);
            return;
          }

          // handle url 
        })
NiVeK92
sumber
9

Saya tidak bisa mengomentari jawaban yang James Daniels berikan, tapi saya rasa ini sangat penting untuk dibaca.

Memberikan URL yang ditandatangani Seperti yang dia lakukan dalam banyak kasus tampaknya sangat buruk dan mungkin Berbahaya . Menurut dokumentasi Firebase, url yang ditandatangani akan kedaluwarsa setelah beberapa waktu, jadi menambahkannya ke databse Anda akan menyebabkan url kosong setelah jangka waktu tertentu.

Mungkin karena salah memahami Dokumentasi di sana dan url yang ditandatangani tidak kedaluwarsa, yang akan menyebabkan beberapa masalah keamanan. Kunci tampaknya sama untuk setiap file yang diunggah. Ini berarti begitu Anda mendapatkan url dari satu file, seseorang dapat dengan mudah mengakses file yang seharusnya tidak dia akses, hanya dengan mengetahui namanya.

Jika saya salah paham maka saya akan lvoe untuk dikoreksi. Orang lain mungkin harus memperbarui solusi bernama di atas. Jika saya mungkin salah di sana

Renji
sumber
7

Inilah yang saya gunakan saat ini, sederhana dan berfungsi dengan sempurna.

Anda tidak perlu melakukan apa pun dengan Google Cloud. Ini berfungsi di luar kotak dengan Firebase ..

// Save the base64 to storage.
const file = admin.storage().bucket('url found on the storage part of firebase').file(`profile_photos/${uid}`);
await file.save(base64Image, {
    metadata: {
      contentType: 'image/jpeg',
    },
    predefinedAcl: 'publicRead'
});
const metaData = await file.getMetadata()
const url = metaData[0].mediaLink

EDIT: Contoh yang sama, tetapi dengan unggahan:

await bucket.upload(fromFilePath, {destination: toFilePath});
file = bucket.file(toFilePath);
metaData = await file.getMetadata()
const trimUrl = metaData[0].mediaLink

memperbarui:

tidak perlu melakukan dua panggilan berbeda dalam metode unggah untuk mendapatkan metadata:

let file = await bucket.upload(fromFilePath, {destination: toFilePath});
const trimUrl = file[0].metaData.mediaLink
Oliver Dixon
sumber
1
Bagaimana Anda menggunakannya dengan file yang tidak dikodekan base64?
Tibor Udvari
1
Ini bukan mediaLinkenter, ini hanya mediaLink
l2aelba
1
Saya tidak dapat menemukan mediaLink i.stack.imgur.com/B4Fw5.png
sarah
@ Sarah Saya menulis ini menggunakan skrip, tidak yakin apakah ada beberapa modul pengganti.
Oliver Dixon
3

Saya memiliki masalah yang sama, namun, saya melihat kode contoh fungsi firebase, bukan README. Dan Jawaban di utas ini juga tidak membantu ...

Anda dapat menghindari meneruskan file konfigurasi dengan melakukan hal berikut:

Buka Cloud Console proyek Anda > IAM & admin> IAM , Temukan akun layanan default App Engine dan tambahkan peran Service Account Token Creator ke anggota tersebut. Ini akan memungkinkan aplikasi Anda membuat URL publik yang ditandatangani ke gambar.

sumber: Secara otomatis menghasilkan fungsi Gambar Mini README

Peran Anda untuk mesin aplikasi akan terlihat seperti ini:

Cloud Console

TheFullResolution
sumber
3

Jika Anda menggunakan nilai daftar kontrol akses yang telah ditentukan sebelumnya dari 'publicRead', Anda dapat mengunggah file dan mengaksesnya dengan struktur url yang sangat sederhana:

// Upload to GCS
const opts: UploadOptions = {
  gzip: true,
  destination: dest, // 'someFolder/image.jpg'
  predefinedAcl: 'publicRead',
  public: true
};
return bucket.upload(imagePath, opts);

Anda kemudian dapat membuat url seperti ini:

const storageRoot = 'https://storage.googleapis.com/';
const bucketName = 'myapp.appspot.com/'; // CHANGE TO YOUR BUCKET NAME
const downloadUrl = storageRoot + bucketName + encodeURIComponent(dest);
anorganik
sumber
2

Ini berfungsi jika Anda hanya membutuhkan file publik dengan URL sederhana. Perhatikan bahwa ini dapat mengesampingkan aturan penyimpanan Firebase Anda.

bucket.upload(file, function(err, file) {
    if (!err) {
      //Make the file public
      file.acl.add({
      entity: 'allUsers',
      role: gcs.acl.READER_ROLE
      }, function(err, aclObject) {
          if (!err) {
              var URL = "https://storage.googleapis.com/[your bucket name]/" + file.id;
              console.log(URL);
          } else {
              console.log("Failed to set permissions: " + err);
          }
      });  
    } else {
        console.log("Upload failed: " + err);
    }
});
Dakine
sumber
1

Bagi mereka yang menggunakan SDK Firebase dan admin.initializeApp:

1 - Buat Kunci Pribadi dan tempatkan di folder / functions.

2 - Konfigurasi kode Anda sebagai berikut:

const serviceAccount = require('../../serviceAccountKey.json');
try { admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) })); } catch (e) {}

Dokumentasi

Coba / tangkap adalah karena saya menggunakan index.js yang mengimpor file lain dan membuat satu fungsi untuk setiap file. Jika Anda menggunakan satu file index.js dengan semua fungsi, Anda tidak masalah admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.

Allan Poppe
sumber
bagi saya itu adalah '../serviceaccountkey.json' tapi terima kasih atas perhatiannya untuk menggunakan ../
robert king
1

Sejak firebase 6.0.0 saya dapat mengakses penyimpanan secara langsung dengan admin seperti ini:

const bucket = admin.storage().bucket();

Jadi saya tidak perlu menambahkan akun layanan. Kemudian menyetel UUID seperti yang dirujuk di atas berfungsi untuk mendapatkan url firebase.

NickJ
sumber
1

Ini yang terbaik yang pernah saya lakukan. Itu mubazir, tetapi satu-satunya solusi yang masuk akal yang berhasil untuk saya.

await bucket.upload(localFilePath, {destination: uploadPath, public: true});
const f = await bucket.file(uploadPath)
const meta = await f.getMetadata()
console.log(meta[0].mediaLink)
Tibor Udvari
sumber
1

Tanpa signedURL()menggunakanmakePublic()

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp()
var bucket = admin.storage().bucket();

// --- [Above] for admin related operations, [Below] for making a public url from a GCS uploaded object

const { Storage } = require('@google-cloud/storage');
const storage = new Storage();

exports.testDlUrl = functions.storage.object().onFinalize(async (objMetadata) => {
    console.log('bucket, file', objMetadata.bucket + ' ' + objMetadata.name.split('/').pop()); // assuming file is in folder
    return storage.bucket(objMetadata.bucket).file(objMetadata.name).makePublic().then(function (data) {
        return admin.firestore().collection('publicUrl').doc().set({ publicUrl: 'https://storage.googleapis.com/' + objMetadata.bucket + '/' + objMetadata.name }).then(writeResult => {
            return console.log('publicUrl', writeResult);
        });
    });
});
ersin-ertan
sumber
1

jawaban oleh https://stackoverflow.com/users/269447/laurent bekerja paling baik

const uploadOptions: UploadOptions = {
    public: true
};

const bucket = admin.storage().bucket();
[ffile] = await bucket.upload(oPath, uploadOptions);
ffile.metadata.mediaLink // this is what you need
Jasdeep Singh
sumber
0

Jika Anda mendapatkan kesalahan:

Google Cloud Functions: memerlukan (…) bukanlah sebuah fungsi

coba ini:

const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: 'service-account-key.json'});
const bucket = storage.bucket(object.bucket);
const file = bucket.file(filePath);
.....
Kambing Liar
sumber
0

Saya sudah memposting jawaban saya ... di bawah URL Dimana Anda bisa mendapatkan kode lengkap dengan solusi

Bagaimana cara mengupload gambar (string) berenkode base64 langsung ke keranjang Google Cloud Storage menggunakan Node.js?

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
        "client_email": "[email protected]",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);
Rawan-25
sumber