Holen Sie sich die Download-URL aus einer Datei, die mit Cloud Functions for Firebase hochgeladen wurde

122

Nach dem Hochladen einer Datei in Firebase Storage mit Funktionen für Firebase möchte ich die Download-URL der Datei erhalten.

Ich habe das :

...

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

        // Get the download url of file

    });

Die Objektdatei enthält viele Parameter. Sogar einer mit Namen mediaLink. Wenn ich jedoch versuche, auf diesen Link zuzugreifen, wird folgende Fehlermeldung angezeigt:

Anonyme Benutzer haben keinen Zugriff auf storage.objects.get auf Objekt ...

Kann mir jemand sagen, wie ich die öffentliche Download-URL bekomme?

Danke dir

Valentin
quelle
Siehe auch diesen Beitrag, in dem die URL aus den in der Funktion verfügbaren Daten rekonstruiert wird.
Kato

Antworten:

132

Sie müssen eine signierte URL mit getSignedURL über das NPM-Modul @ google-cloud / storage generieren .

Beispiel:

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

Sie müssen @google-cloud/storagemit den Anmeldeinformationen Ihres Dienstkontos initialisieren, da die Standardanmeldeinformationen der Anwendung nicht ausreichen.

UPDATE : Auf das Cloud Storage SDK kann jetzt über das Firebase Admin SDK zugegriffen werden, das als Wrapper für @ google-cloud / storage fungiert. Der einzige Weg ist, wenn Sie entweder:

  1. Initiieren Sie das SDK mit einem speziellen Dienstkonto, normalerweise über eine zweite, nicht standardmäßige Instanz.
  2. Oder geben Sie dem Standard-App Engine-Dienstkonto ohne Dienstkonto die Berechtigung "signBlob".
James Daniels
quelle
74
Das ist merkwürdig. Mit dem Firebase Android-, iOS- und Web-SDK können wir die Download-URL problemlos von einer Speicherreferenz abrufen. Warum ist es nicht so einfach, im Admin zu sein? PS: Wo finde ich die 'service-account.json', die zum Initialisieren von gcs benötigt wird?
Valentin
2
Dies liegt daran, dass der admin-sdk keine Cloud-Speicher-Ergänzungen enthält. Sie können Ihr admin-sdk-Dienstkonto json hier herunterladen console.firebase.google.com/project/_/settings/serviceaccounts/…
James Daniels
18
Die mit dieser Methode generierte URL ist lächerlich lang. Die durch die von @martemorfosis vorgeschlagene Methode generierte URL ist viel besser. Gibt es eine Funktion, die diese URL erzeugt? Das speichere ich in der Datenbank für die zukünftige Verwendung, wenn ich firebase-sdk verwende. In der Funktionsdomäne muss eine Spiegelmethode vorhanden sein.
Bogac
3
Wie können wir die Datei service-account.json entlang der bereitgestellten Funktionen hochladen? Ich habe versucht, es im Funktionsordner abzulegen und im Dateifeld in package.json zu referenzieren, aber es wird nicht bereitgestellt. Danke dir.
David Aroesti
2
Müssen wir hinzufügen actionund expires?
Chad Bingham
80

Hier ist ein Beispiel zum Festlegen des Download-Tokens beim Hochladen:

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

dann mit anrufen

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

Der Schlüssel hier ist, dass metadatain der metadataOptionseigenschaft ein Objekt verschachtelt ist . Wenn Sie firebaseStorageDownloadTokenseinen uuid-v4-Wert festlegen, wird Cloud Storage angewiesen, diesen Wert als öffentliches Authentifizierungstoken zu verwenden.

Vielen Dank an @martemorfosis

Drew Beaupre
quelle
Wie erhalte ich ein gültiges UUID-Token für eine Datei, die bereits im Speicher hochgeladen wurde? Das Generieren einer zufälligen UUID hat nicht geholfen. Irgendwelche Hinweise?
DerFaizio
3
Die Antwort wurde in @martemorfosis post gefunden. Die UUID kann aus der Datei object.metadata exports.uploadProfilePic = functions.storage.object (). OnChange (event => {const object = event.data; // Das Speicherobjekt. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio
Vielen Dank für das Eimer Beispiel! Ich habe fast 1 Stunde lang verschiedene Kombinationen für die
Bucket- und Dateimethoden ausprobiert
1
Danke für deine Antwort! In meinem Fall habe ich mit bucket.file (Dateiname) .createWriteStream hochgeladen, der nach Abschluss des Uploads keine Daten zurückgibt. Daher habe ich encodeURIComponent (Dateiname) anstelle von encodeURIComponent (Dateiname) verwendet.
Stanislau Buzunko
2
Dies sollte die richtige Antwort sein. Das Ergebnis ist eine URL, die der von den Firebase-SDKs (@DevMike) generierten ähnelt, und ich wette, dass sie genau das tun, was sie hinter den Kulissen tun.
Samuel E.
63

In dieser Antwort werden die Optionen zum Abrufen der Download-URL beim Hochladen einer Datei in Google / Firebase Cloud Storage zusammengefasst. Es gibt drei Arten von Download-URLs:

  1. signierte Download-URLs, die temporär sind und Sicherheitsfunktionen aufweisen
  2. Token-Download-URLs, die dauerhaft sind und Sicherheitsfunktionen aufweisen
  3. öffentliche Download-URLs, die dauerhaft sind und keine Sicherheit bieten

Es gibt drei Möglichkeiten, eine Token-Download-URL abzurufen. Die beiden anderen Download-URLs haben nur eine Möglichkeit, sie abzurufen.

Von der Firebase-Speicherkonsole

Sie können die Download-URL von der Firebase-Speicherkonsole abrufen:

Geben Sie hier die Bildbeschreibung ein

Die Download-URL sieht folgendermaßen aus:

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

Der erste Teil ist ein Standardpfad zu Ihrer Datei. Am Ende steht der Token. Diese Download-URL ist permanent, dh sie läuft nicht ab, obwohl Sie sie widerrufen können.

getDownloadURL () Vom Frontend

Die Dokumentation fordert uns auf, Folgendes zu verwenden getDownloadURL():

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

Dadurch wird dieselbe Download-URL abgerufen, die Sie von Ihrer Firebase-Speicherkonsole erhalten können. Diese Methode ist einfach, erfordert jedoch, dass Sie den Pfad zu Ihrer Datei kennen, der in meiner App etwa 300 Codezeilen umfasst, um eine relativ einfache Datenbankstruktur zu erhalten. Wenn Ihre Datenbank komplex ist, wäre dies ein Albtraum. Sie könnten Dateien vom Front-End hochladen, aber dies würde Ihre Anmeldeinformationen jedem zugänglich machen, der Ihre App herunterlädt. Bei den meisten Projekten möchten Sie Ihre Dateien von Ihrem Node-Backend oder von Google Cloud-Funktionen hochladen, dann die Download-URL abrufen und zusammen mit anderen Daten zu Ihrer Datei in Ihrer Datenbank speichern.

getSignedUrl () für temporäre Download-URLs

getSignedUrl () ist einfach über ein Node- Backend oder Google Cloud-Funktionen zu verwenden:

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

Eine signierte Download-URL sieht folgendermaßen aus:

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

Die signierte URL hat ein Ablaufdatum und eine lange Signatur. Die Dokumentation für die Befehlszeile gsutil signurl -d besagt, dass signierte URLs nur vorübergehend sind: Der Standardablauf beträgt eine Stunde und der maximale Ablauf sieben Tage.

Ich werde hier schimpfen, dass getSignedUrl niemals sagt, dass Ihre signierte URL in einer Woche abläuft. Der Dokumentationscode hat 3-17-2025das Ablaufdatum, was darauf hindeutet, dass Sie die Ablaufjahre in der Zukunft festlegen können. Meine App funktionierte perfekt und stürzte eine Woche später ab. Die Fehlermeldung besagte, dass die Signaturen nicht übereinstimmten und die Download-URL nicht abgelaufen war. Ich habe verschiedene Änderungen an meinem Code vorgenommen und alles hat funktioniert ... bis eine Woche später alles abstürzte. Dies dauerte mehr als einen Monat der Frustration.

Machen Sie Ihre Datei öffentlich verfügbar

Sie können die Berechtigungen für Ihre Datei so festlegen, dass sie öffentlich gelesen werden können, wie in der Dokumentation erläutert . Dies kann über den Cloud-Speicherbrowser oder von Ihrem Knotenserver aus erfolgen. Sie können eine Datei oder ein Verzeichnis oder Ihre gesamte Speicherdatenbank öffentlich machen. Hier ist der Knotencode:

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

Das Ergebnis sieht in Ihrem Cloud-Speicherbrowser folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

Jeder kann dann den Standardpfad verwenden, um Ihre Datei herunterzuladen:

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

Eine andere Möglichkeit, eine Datei öffentlich zu machen, ist die Verwendung der Methode makePublic () . Ich habe es nicht geschafft, dies zum Laufen zu bringen. Es ist schwierig, die richtigen Bucket- und Dateipfade zu finden.

Eine interessante Alternative ist die Verwendung von Zugriffssteuerungslisten . Sie können eine Datei nur Benutzern zur Verfügung stellen, die Sie in eine Liste aufgenommen haben, oder sie verwenden authenticatedRead, um die Datei allen Benutzern zur Verfügung zu stellen, die über ein Google-Konto angemeldet sind. Wenn es eine Option "Jeder, der sich mit Firebase Auth bei meiner App angemeldet hat" gäbe, würde ich diese verwenden, da dies den Zugriff nur auf meine Benutzer beschränken würde.

Erstellen Sie Ihre eigene Download-URL mit firebaseStorageDownloadTokens

Mehrere Antworten beschreiben eine undokumentierte Google Storage-Objekteigenschaft firebaseStorageDownloadTokens. Damit können Sie Storage das Token mitteilen, das Sie verwenden möchten. Sie können mit dem uuidKnotenmodul ein Token generieren . Vier Codezeilen und Sie können Ihre eigene Download-URL erstellen, dieselbe Download-URL, die Sie von der Konsole oder erhalten getDownloadURL(). Die vier Codezeilen sind:

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

Hier ist der Code im Kontext:

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

Das ist kein Tippfehler - Sie müssen firebaseStorageDownloadTokensin doppelten Schichten von nisten metadata:!

Doug Stevenson wies darauf hin, dass dies firebaseStorageDownloadTokenskeine offizielle Google Cloud Storage-Funktion ist. Sie werden es in keiner Google-Dokumentation finden, und es gibt kein Versprechen, dass es in einer zukünftigen Version von sein wird @google-cloud. Ich mag es, firebaseStorageDownloadTokensweil es der einzige Weg ist, das zu bekommen, was ich will, aber es hat einen "Geruch", dessen Verwendung nicht sicher ist.

Warum kein getDownloadURL () vom Knoten?

Wie @Clinton schrieb, sollte Google file.getDownloadURL()eine Methode in @google-cloud/storage(dh Ihrem Node- Backend) erstellen . Ich möchte eine Datei von Google Cloud Functions hochladen und die Token-Download-URL erhalten.

Thomas David Kehoe
quelle
10
Ich habe ein Problem @google-cloud/storagedafür erstellt, zögern Sie nicht +1;) github.com/googleapis/nodejs-storage/issues/697
Théo Champion
1
letzter makePublic () Link.
Galki
1
Es scheint, dass das firebaseStorageDownloadTokensnicht mehr funktioniert.
Mason
1
Die akzeptierte Antwort deutet darauf hin, dass es nicht möglich ist, eine dauerhafte Download-URL zu erhalten, die nicht abläuft und nicht korrekt ist. Das Detail hier in Ihrer Antwort ist ausgezeichnet und sollte als die richtige Antwort markiert werden. Danke dir.
DevMike
2
@ Thomas danke für die tolle Zusammenfassung! Sie haben erwähnt, dass es drei Möglichkeiten gibt, eine permanente Token-Download-URL abzurufen, aber Sie haben nur zwei freigegeben: (a) Von der Firebase-Speicherkonsole und (b) getDownloadURL () Vom Front-End. Ich frage mich, was ist der 3. Weg?
czphilip
23

Mit den jüngsten Änderungen in den Funktionen Objekt Antwort können Sie alles , was Sie brauchen , um „Stich“ zusammen die Download - URL wie so erhalten:

 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.
quelle
2
Beziehen Sie sich auf die Objektantwort von bucket.file().upload()? Ich erhalte keine Metadateneigenschaft in den Antwortdaten und bin mir nicht sicher, wie ich diese erhalten soll firebaseStorageDownloadTokens.
Dygerati
auch [IHR EIMER] ist bucket.name, Sie müssen es nicht fest codieren oder eine zusätzliche lokale
Variable verwenden
4
Das Problem bei dieser Lösung ist, dass die Service-URL fest codiert ist. Wenn die Firebase / Google es ändert, kann es brechen. Die Verwendung der metadata.mediaLinkEigenschaft verhindert ein solches Problem.
Laurent
2
Es wird nicht unterstützt, eine URL wie diese zu erstellen. Es mag heute funktionieren, könnte aber in Zukunft kaputt gehen. Sie sollten nur die bereitgestellten APIs verwenden, um eine ordnungsgemäße Download-URL zu generieren.
Doug Stevenson
1
Es ist eine schlechte Wahl, sich auf eine fest codierte URL zu verlassen, die sich möglicherweise ändert.
Laurent
23

Wenn Sie an einem Firebase-Projekt arbeiten, können Sie signierte URLs in einer Cloud-Funktion erstellen, ohne andere Bibliotheken einzuschließen oder eine Anmeldeinformationsdatei herunterzuladen. Sie müssen nur die IAM-API aktivieren und Ihrem vorhandenen Dienstkonto eine Rolle hinzufügen (siehe unten).

Initialisieren Sie die Admin-Bibliothek und erhalten Sie eine Dateireferenz wie gewohnt:

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

Anschließend generieren Sie eine signierte URL mit

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

Stellen Sie sicher, dass Ihr Firebase-Dienstkonto über ausreichende Berechtigungen verfügt, um dies auszuführen

  1. Gehen Sie zur Google API-Konsole und aktivieren Sie die IAM-API ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview ).
  2. Gehen Sie noch in der API-Konsole zum Hauptmenü "IAM & admin" -> "IAM".
  3. Klicken Sie für die Rolle "App Engine-Standarddienstkonto" auf "Bearbeiten"
  4. Klicken Sie auf "Weitere Rolle hinzufügen" und fügen Sie die mit dem Namen "Service Account Token Creator" hinzu.
  5. Speichern Sie und warten Sie eine Minute, bis sich die Änderungen verbreitet haben

Bei einer Vanilla Firebase-Konfiguration wird beim ersten Ausführen des obigen Codes eine Fehlermeldung angezeigt. Die IAM-API (Identity and Access Management) wurde zuvor in Projekt XXXXXX nicht verwendet oder ist deaktiviert. . Wenn Sie dem Link in der Fehlermeldung folgen und die IAM-API aktivieren, wird ein weiterer Fehler angezeigt : Die Berechtigung iam.serviceAccounts.signBlob ist erforderlich, um diesen Vorgang für das Dienstkonto my-service-account auszuführen . Durch Hinzufügen der Token Creator-Rolle wird dieses zweite Berechtigungsproblem behoben.

SMX
quelle
Ich wollte gerade eine Antwort mit im Grunde den gleichen Details hinterlassen, die ich ENDLICH auf die harte Tour herausgefunden hatte - ich wünschte, ich hätte die Lösungen so weit unten durchgelesen: / Das hat bei mir ab dem 12.12.18 funktioniert. Vielen Dank für die ausführliche Anleitung, sehr hilfreich für uns Anfänger !!
Kat
2
Meine signierte URL läuft in 2 Wochen ab, aber ich verwende admin.initializeApp () ohne Schlüssel. Ist dies das Problem? Ich hatte das Standarddienstkonto der App Engine-App auf "Eigentümer" und den Cloud-Funktionsdienstagenten eingestellt. Ich habe gerade "Eigentümer" entfernt und "Dienstkonto-Token-Ersteller" hinzugefügt
Amit Bravo
2
Signierte URLs verfallen in 7 Tagen. Sie können ein kürzeres Ablaufdatum festlegen, jedoch nicht länger.
Thomas David Kehoe
Wie aktualisiere ich die URL, wenn sie abläuft?
Manoj MM
Wie aktualisiere ich die URL, um sie auf eine längere Zeit einzustellen?
Saifallak
16

Eine Methode, die ich mit Erfolg verwende, besteht darin, einen UUID v4-Wert auf einen Schlüssel festzulegen, der firebaseStorageDownloadTokensin den Metadaten der Datei nach Abschluss des Uploads benannt ist, und dann die Download-URL gemäß der Struktur, die Firebase zum Generieren dieser URLs verwendet, selbst zusammenzustellen, z.

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

Ich weiß nicht, wie viel "sicher" die Verwendung dieser Methode ist (da Firebase in Zukunft die Generierung der Download-URLs ändern könnte), aber sie ist einfach zu implementieren.

Martemorfose
quelle
1
Haben Sie ein Beispiel, in dem Sie den UUID-Wert festlegen?
Drew Beaupre
1
Ich habe die gleiche Frage wie Drew, wo legen Sie die Metadaten fest? Ich habe versucht, während der Bucket.upload-Funktion einzustellen, hat nicht funktioniert.
Vysakh Sreenivasan
1
Vysakh, ich habe eine vollständige Antwort mit Beispiel gepostet. Hoffe das hilft dir.
Drew Beaupre
Wo / wie erstellen Sie den Token?
CodyBugstein
3
Ich würde diese Technik nicht als "sicher" betrachten, da Download-URLs undurchsichtig sein sollen und deren Komponenten nicht zerlegt oder zusammengesetzt werden dürfen.
Doug Stevenson
16

Für diejenigen, die sich fragen, wohin die Firebase Admin SDK-Datei serviceAccountKey.json gehen soll. Legen Sie es einfach in den Funktionsordner und stellen Sie es wie gewohnt bereit.

Es verwirrt mich immer noch, warum wir nicht einfach die Download-URL aus den Metadaten abrufen können, wie wir es im Javascript SDK tun. Es ist nicht wünschenswert, eine URL zu generieren, die irgendwann abläuft, und sie in der Datenbank zu speichern.

Clinton
quelle
15

Ich schlage vor, die Option predefinedAcl: 'publicRead'beim Hochladen einer Datei mit Cloud Storage NodeJS 1.6.x oder + zu verwenden:

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

bucket.upload(attachment, options);

Das Abrufen der öffentlichen URL ist dann so einfach wie:

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
quelle
2
Das scheint tatsächlich zu funktionieren. Der einzige Nachteil, den ich bisher sehe, ist, dass wenn Sie das Bild in der URL-Leiste eines Browsers drücken, das Bild heruntergeladen wird, anstatt es inline anzuzeigen.
Michael Giovanni Pumo
file.getMetadata () hat den Trick für mich gemacht, nachdem ich die save () -Methode für die Dateireferenz verwendet habe. Verwendung in NodeJS mit firebase-admin sdk.
Pascal Lamers
hat nicht funktioniert, ich bekomme anonymen Anrufer hat keinen Speicher.objects.get Zugriff auf your_app / image.jpg
Manoj MM
9

Entschuldigung, aber ich kann wegen des fehlenden Rufs keinen Kommentar zu Ihrer Frage oben posten, daher werde ich ihn in diese Antwort aufnehmen.

Gehen Sie wie oben angegeben vor, indem Sie eine signierte URL generieren, aber anstatt das service-account.json zu verwenden, müssen Sie meines Erachtens das serviceAccountKey.json verwenden, das Sie unter generieren können (ersetzen Sie YOURPROJECTID entsprechend).

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

Beispiel:

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
quelle
9

Ich kann die Antwort von James Daniels nicht kommentieren, aber ich denke, das ist sehr wichtig zu lesen.

Eine signierte URL herauszugeben Wie er es getan hat, scheint in vielen Fällen ziemlich schlecht und möglicherweise gefährlich zu sein . Laut der Dokumentation von Firebase läuft die signierte URL nach einiger Zeit ab. Wenn Sie diese also zu Ihrer Datenbank hinzufügen, wird nach einem bestimmten Zeitraum eine leere URL angezeigt

Es kann sein, dass die Dokumentation dort falsch verstanden wurde und die signierte URL nicht abläuft, was zu Sicherheitsproblemen führen würde. Der Schlüssel scheint für jede hochgeladene Datei gleich zu sein. Dies bedeutet, dass jemand, sobald Sie die URL einer Datei erhalten haben, leicht auf Dateien zugreifen kann, auf die er nicht zugreifen soll, indem er nur deren Namen kennt.

Wenn ich das missverstehen würde, müsste ich korrigiert werden. Andernfalls sollte wahrscheinlich jemand die oben genannte Lösung aktualisieren. Wenn ich mich da irre

Renji
quelle
7

Dies ist, was ich derzeit benutze, es ist einfach und es funktioniert einwandfrei.

Sie müssen mit Google Cloud nichts tun. Mit Firebase funktioniert es sofort.

// 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: Gleiches Beispiel, aber mit Upload:

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

aktualisieren:

Es sind keine zwei unterschiedlichen Aufrufe beim Hochladen erforderlich, um die Metadaten abzurufen:

let file = await bucket.upload(fromFilePath, {destination: toFilePath});
const trimUrl = file[0].metaData.mediaLink
Oliver Dixon
quelle
1
Wie würden Sie es mit einer Datei verwenden, die nicht base64-codiert ist?
Tibor Udvari
1
Es ist nicht mediaLinkenter, es ist nur mediaLink
l2aelba
Ich kann mediaLink i.stack.imgur.com/B4Fw5.png
sarah
@ Sarah Ich habe dies mit Typoskript geschrieben und bin mir nicht sicher, ob es einen Modulersatz gibt.
Oliver Dixon
3

Ich hatte das gleiche Problem, aber ich habe mir den Code des Firebase-Funktionsbeispiels anstelle der README angesehen. Und Antworten auf diesen Thread haben auch nicht geholfen ...

Sie können das Übergeben der Konfigurationsdatei vermeiden, indem Sie folgende Schritte ausführen:

Gehen Sie zu Cloud Console> IAM & admin> IAM Ihres Projekts, suchen Sie das App Engine-Standarddienstkonto und fügen Sie diesem Mitglied die Rolle des Dienstkonten-Token-Erstellers hinzu. Auf diese Weise kann Ihre App signierte öffentliche URLs zu den Bildern erstellen.

Quelle: Thumbnails-Funktion README automatisch generieren

Ihre Rolle für die App Engine sollte folgendermaßen aussehen:

Cloud-Konsole

TheFullResolution
quelle
3

Wenn Sie den vordefinierten Zugriffssteuerungslistenwert 'publicRead' verwenden, können Sie die Datei hochladen und mit einer sehr einfachen URL-Struktur darauf zugreifen:

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

Sie können die URL dann folgendermaßen erstellen:

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

Dies funktioniert, wenn Sie nur eine öffentliche Datei mit einer einfachen URL benötigen. Beachten Sie, dass dies Ihre Firebase-Speicherregeln außer Kraft setzen kann.

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
quelle
1

Für diejenigen, die Firebase SDK verwenden und admin.initializeApp:

1 - Generieren Sie einen privaten Schlüssel und legen Sie ihn im Ordner / functions ab.

2 - Konfigurieren Sie Ihren Code wie folgt:

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

Dokumentation

Der Versuch / Fang ist, weil ich eine index.js verwende, die andere Dateien importiert und eine Funktion für jede Datei erstellt. Wenn Sie eine einzelne index.js-Datei mit allen Funktionen verwenden, sollten Sie damit einverstanden sein admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.

Allan Poppe
quelle
Für mich war es '../serviceaccountkey.json', aber danke, dass die Heads-Ups den ../
Robert King
1

Ab Firebase 6.0.0 konnte ich wie folgt direkt mit dem Administrator auf den Speicher zugreifen:

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

Ich musste also kein Dienstkonto hinzufügen. Das Einstellen der UUID wie oben angegeben hat zum Abrufen der Firebase-URL funktioniert.

NickJ
quelle
1

Dies ist das Beste, was ich mir ausgedacht habe. Es ist überflüssig, aber die einzige vernünftige Lösung, die für mich funktioniert hat.

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
quelle
1

Ohne zu signedURL()benutzenmakePublic()

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
quelle
1

Antwort von https://stackoverflow.com/users/269447/laurent funktioniert am besten

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
quelle
0

Wenn Sie eine Fehlermeldung erhalten:

Google Cloud-Funktionen: require (…) ist keine Funktion

Versuche dies:

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);
.....
Wilde Ziege
quelle
0

Ich poste meine Antwort bereits ... unter der URL, unter der Sie den vollständigen Code mit Lösung erhalten können

Wie lade ich ein Base64-codiertes Bild (Zeichenfolge) mit Node.js direkt in einen Google Cloud Storage-Bucket hoch?

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
quelle