Obtenga la URL de descarga del archivo cargado con Cloud Functions para Firebase


125

Después de cargar un archivo en Firebase Storage con Funciones para Firebase, me gustaría obtener la URL de descarga del archivo.

Tengo esto :

...

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

        // Get the download url of file

    });

El archivo de objeto tiene muchos parámetros. Incluso uno nombrado mediaLink. Sin embargo, si intento acceder a este enlace, aparece este error:

Los usuarios anónimos no tienen acceso storage.objects.get al objeto ...

¿Alguien puede decirme cómo obtener la URL de descarga pública?

Gracias


Consulte también esta publicación que reconstruye la URL a partir de los datos disponibles en la función.
Kato

Respuestas:


134

Deberá generar una URL firmada mediante getSignedURL a través del módulo NPM @ google-cloud / storage .

Ejemplo:

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

Deberá inicializar @google-cloud/storagecon las credenciales de su cuenta de servicio, ya que las credenciales predeterminadas de la aplicación no serán suficientes.

ACTUALIZACIÓN : Ahora se puede acceder al SDK de Cloud Storage a través del SDK de Firebase Admin, que actúa como un contenedor de @ google-cloud / storage. La única forma en que lo hará es si usted:

  1. Inicie el SDK con una cuenta de servicio especial, generalmente a través de una segunda instancia no predeterminada.
  2. O, sin una cuenta de servicio, otorgando a la cuenta de servicio de App Engine predeterminada el permiso "signBlob".

74
Esto es extraño. Podemos obtener fácilmente la URL de descarga de una referencia de almacenamiento cuando usamos Firebase Android, iOS y Web SDK. ¿Por qué no es tan fácil estar en administración? PD: ¿Dónde puedo encontrar el 'service-account.json' necesario para inicializar gcs?
Valentin

2
Esto se debe a que admin-sdk no tiene adiciones de Cloud Storage. Puede obtener su cuenta de servicio admin-sdk json aquí console.firebase.google.com/project/_/settings/serviceaccounts/…
James Daniels

18
La URL generada con este método es ridículamente larga. La URL generada por el método propuesto @martemorfosis es mucho mejor. ¿Existe alguna función que produzca esa URL? Eso es lo que guardo en la base de datos para uso futuro cuando estoy usando firebase-sdk. Debe existir un método espejo en el dominio de funciones.
Bogac

3
¿Cómo podemos cargar service-account.json junto con las funciones implementadas? Intenté colocarlo en la carpeta de funciones y hacer referencia a él en el campo del archivo en package.json, pero no se está implementando. Gracias.
David Aroesti

2
¿Estamos obligados a agregar actiony expires?
Chad Bingham

83

A continuación, se muestra un ejemplo sobre cómo especificar el token de descarga en la carga:

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

entonces llama con

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

La clave aquí es que hay un metadataobjeto anidado dentro de la metadatapropiedad de la opción. Establecer firebaseStorageDownloadTokensun valor uuid-v4 le indicará a Cloud Storage que lo use como su token de autenticación público.

Muchas gracias a @martemorfosis


¿Cómo obtengo un token UUID válido para un archivo que ya está cargado en Storage? La generación de UUID aleatoria no ayudó. ¿Algún consejo?
DerFaizio

3
Encontré la respuesta en la publicación de @martemorfosis. El UUID se puede recuperar de object.metadata export.uploadProfilePic = functions.storage.object (). OnChange (event => {const object = event.data; // The Storage object. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio

¡Gracias por el ejemplo del cubo! Estuve probando diferentes combinaciones para los métodos de cubo y archivo durante casi 1 hora :)
JCarlosR

1
¡Gracias por tu respuesta! En mi caso, estaba subiendo con bucket.file (fileName) .createWriteStream que no devuelve datos cuando finaliza la carga, como resultado, usé encodeURIComponent (fileName) en lugar de encodeURIComponent (file.name).
Stanislau Buzunko

2
Esta debería ser la respuesta correcta. Da como resultado una URL similar a la generada por los SDK de Firebase (@DevMike), y apuesto a que es exactamente lo que hacen detrás de escena.
Samuel E.

64

Esta respuesta resumirá las opciones para obtener la URL de descarga al cargar un archivo en Google / Firebase Cloud Storage. Hay tres tipos de URL de descarga:

  1. URL de descarga firmadas, que son temporales y tienen funciones de seguridad
  2. URL de descarga de token, que son persistentes y tienen características de seguridad
  3. URL de descarga públicas, que son persistentes y carecen de seguridad

Hay tres formas de obtener una URL de descarga de token. Las otras dos URL de descarga solo tienen una forma de obtenerlas.

Desde Firebase Storage Console

Puede obtener la URL de descarga desde la consola de Firebase Storage:

ingrese la descripción de la imagen aquí

La URL de descarga se ve así:

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

La primera parte es una ruta estándar a su archivo. Al final está la ficha. Esta URL de descarga es permanente, es decir, no caducará, aunque puede revocarla.

getDownloadURL () desde la interfaz

La documentación nos dice que usemos getDownloadURL():

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

Esto obtiene la misma URL de descarga que puede obtener de su consola de Firebase Storage. Este método es fácil pero requiere que conozca la ruta a su archivo, que en mi aplicación es de aproximadamente 300 líneas de código, para una estructura de base de datos relativamente simple. Si su base de datos es compleja, esto sería una pesadilla. Y podría cargar archivos desde la interfaz, pero esto expondría sus credenciales a cualquiera que descargue su aplicación. Entonces, para la mayoría de los proyectos, querrá cargar sus archivos desde su back-end de Node o Google Cloud Functions, luego obtenga la URL de descarga y guárdela en su base de datos junto con otros datos sobre su archivo.

getSignedUrl () para URL de descarga temporal

getSignedUrl () es fácil de usar desde un back-end de Node o 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);
            }
          });
        });
      });
    });
  }

Una URL de descarga firmada se ve así:

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

La URL firmada tiene una fecha de vencimiento y una firma larga. La documentación de la línea de comandos gsutil signurl -d dice que las URL firmadas son temporales: el vencimiento predeterminado es una hora y el vencimiento máximo es siete días.

Voy a despotricar aquí que getSignedUrl nunca dice que su URL firmada caducará en una semana. El código de documentación tiene 3-17-2025como fecha de vencimiento, lo que sugiere que puede establecer los años de vencimiento en el futuro. Mi aplicación funcionó perfectamente y luego se bloqueó una semana después. El mensaje de error decía que las firmas no coincidían, no que la URL de descarga había caducado. Hice varios cambios en mi código y todo funcionó ... hasta que todo falló una semana después. Esto continuó durante más de un mes de frustración.

Haga que su archivo esté disponible públicamente

Puede configurar los permisos en su archivo para lectura pública, como se explica en la documentación . Esto se puede hacer desde el navegador de almacenamiento en la nube o desde su servidor Node. Puede hacer público un archivo o un directorio o toda su base de datos de almacenamiento. Aquí está el código de nodo:

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

El resultado se verá así en su navegador de almacenamiento en la nube:

ingrese la descripción de la imagen aquí

Cualquiera puede usar la ruta estándar para descargar su archivo:

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

Otra forma de hacer público un archivo es usar el método makePublic () . No he podido hacer que esto funcione, es complicado acertar las rutas del depósito y del archivo.

Una alternativa interesante es utilizar listas de control de acceso . Puede hacer que un archivo esté disponible solo para los usuarios que haya incluido en una lista, o usarlo authenticatedReadpara que el archivo esté disponible para cualquier persona que haya iniciado sesión desde una cuenta de Google. Si hubiera una opción "cualquiera que inicie sesión en mi aplicación usando Firebase Auth", la usaría, ya que limitaría el acceso solo a mis usuarios.

Cree su propia URL de descarga con firebaseStorageDownloadTokens

Varias respuestas describen una propiedad de objeto de Google Storage indocumentada firebaseStorageDownloadTokens. Con esto, puede decirle a Storage el token que desea usar. Puede generar un token con el uuidmódulo Node. Cuatro líneas de código y puede crear su propia URL de descarga, la misma URL de descarga que obtiene de la consola o getDownloadURL(). Las cuatro líneas de código son:

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

Aquí está el código en contexto:

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

Eso no es un error tipográfico, ¡tienes que anidar firebaseStorageDownloadTokensen capas dobles de metadata:!

Doug Stevenson señaló que firebaseStorageDownloadTokensno es una función oficial de Google Cloud Storage. No lo encontrará en ninguna documentación de Google, y no hay ninguna promesa de que lo esté en una versión futura de @google-cloud. Me gusta firebaseStorageDownloadTokensporque es la única forma de obtener lo que quiero, pero tiene un "olor" que no es seguro de usar.

¿Por qué No getDownloadURL () de Node?

Como escribió @Clinton, Google debería crear un file.getDownloadURL()método en @google-cloud/storage(es decir, su back-end de Node). Quiero subir un archivo desde Google Cloud Functions y obtener la URL de descarga del token.


10
Creé un problema @google-cloud/storagepara esto, no dudes en
Théo Champion

1
último enlace makePublic () .
galki

1
Parece que firebaseStorageDownloadTokensya no funciona.
Mason

1
La respuesta aceptada sugiere que no es posible obtener una URL de descarga persistente que no caduque, lo cual no es correcto. El detalle aquí en su respuesta es excelente y debe marcarse como la respuesta correcta. Gracias.
DevMike

2
@thomas ¡gracias por el fantástico resumen! Mencionaste que hay 3 formas de obtener una URL de descarga de token persistente, pero compartiste solo 2: (a) Desde Firebase Storage Console y (b) getDownloadURL () Desde el Front End. Me pregunto cuál es la tercera vía.
czphilip

23

Con los cambios recientes en la respuesta del objeto de funciones , puede obtener todo lo que necesita para "unir" la URL de descarga así:

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

2
¿Te refieres a la respuesta del objeto de bucket.file().upload()? No recibo ninguna propiedad de metadatos en los datos de respuesta y no estoy seguro de cómo obtenerlos firebaseStorageDownloadTokens.
Dygerati

también lo es [YOUR BUCKET] bucket.name, no tienes que codificarlo ni usar una var local adicional
Călin Darie

4
El problema con esta solución es que la URL del servicio está codificada. Si Firebase / Google lo cambia, puede romperse. El uso de la metadata.mediaLinkpropiedad evita este problema.
Laurent

2
No es un caso compatible para crear una URL como esta. Puede funcionar hoy, pero podría romperse en el futuro. Solo debe utilizar las API proporcionadas para generar una URL de descarga adecuada.
Doug Stevenson

1
Confiar en una URL codificada que puede cambiar es una mala elección.
Laurent

23

Si está trabajando en un proyecto de Firebase, puede crear URL firmadas en una función de Cloud sin incluir otras bibliotecas ni descargar un archivo de credenciales. Solo necesita habilitar la API de IAM y agregar un rol a su cuenta de servicio existente (ver más abajo).

Inicialice la biblioteca de administración y obtenga una referencia de archivo como lo haría normalmente:

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

Luego genera una URL firmada con

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

Asegúrese de que su cuenta de servicio de Firebase tenga permisos suficientes para ejecutar este

  1. Vaya a la consola de la API de Google y habilite la API de IAM ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )
  2. Aún en la consola de la API, vaya al menú principal, "IAM y administración" -> "IAM"
  3. Haga clic en editar para la función "Cuenta de servicio predeterminada de App Engine".
  4. Haga clic en "Agregar otra función" y agregue la llamada "Creador de tokens de cuenta de servicio".
  5. Guarde y espere un minuto a que se propaguen los cambios

Con una configuración básica de Firebase, la primera vez que ejecute el código anterior, obtendrá un error La API de administración de identidad y acceso (IAM) no se ha utilizado antes en el proyecto XXXXXX o está deshabilitada. . Si sigue el enlace del mensaje de error y habilita la API de IAM, obtendrá otro error: Se requiere el permiso iam.serviceAccounts.signBlob para realizar esta operación en la cuenta de servicio my-service-account . Agregar el rol de Creador de tokens soluciona este segundo problema de permisos.


Estaba a punto de dejar una respuesta con básicamente estos mismos detalles que FINALMENTE descubrí de la manera difícil; seguro que desearía haber leído las soluciones tan abajo antes: / Esto funcionó para mí a partir del 12/12/18. ¡Gracias por las instrucciones detalladas, muy útiles para nosotros los principiantes!
Kat

2
Mi URL firmada vence en 2 semanas pero estoy usando admin.initializeApp () sin clave, ¿es este el problema? Tenía la cuenta de servicio predeterminada de la aplicación de App Engine configurada como "propietario" y agente de servicio de Cloud Functions. Acabo de eliminar "propietario" por ahora y agregué "Creador de tokens de cuenta de servicio"
Amit Bravo

2
Las URL firmadas caducan en 7 días. Puede establecer una fecha de vencimiento más corta pero no más larga.
Thomas David Kehoe

¿Cómo actualizar la URL si caduca?
Manoj MM

¿Cómo actualizar la URL para configurarla en más tiempo?
Saifallak

17

Un método que estoy usando con éxito es establecer un valor UUID v4 en una clave nombrada firebaseStorageDownloadTokensen los metadatos del archivo después de que termine de cargarse y luego ensamblar la URL de descarga siguiendo la estructura que usa Firebase para generar estas URL, por ejemplo:

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

No sé cuánto "seguro" es usar este método (dado que Firebase podría cambiar la forma en que genera las URL de descarga en el futuro), pero es fácil de implementar.


1
¿Tiene un ejemplo en el que establece el valor de uuid?
Drew Beaupre

1
Tengo la misma pregunta que Drew, ¿dónde pones los metadatos? Intenté configurar mientras la función bucket.upload no funcionaba.
Vysakh Sreenivasan

1
Vysakh, he publicado una respuesta completa con ejemplo. Espero que te ayude.
Drew Beaupre

¿Dónde / cómo se crea el token?
CodyBugstein

3
No consideraría esta técnica "segura", ya que las URL de descarga deben ser opacas, cuyos componentes no deben desglosarse ni ensamblarse.
Doug Stevenson

16

Para aquellos que se preguntan dónde debería ir el archivo serviceAccountKey.json del SDK de Firebase Admin. Simplemente colóquelo en la carpeta de funciones e impleméntelo como de costumbre.

Todavía me desconcierta por qué no podemos simplemente obtener la URL de descarga de los metadatos como lo hacemos en el SDK de Javascript. No es deseable generar una URL que eventualmente caduque y guardarla en la base de datos.


15

Sugiero usar la opción predefinedAcl: 'publicRead'al cargar un archivo con Cloud Storage NodeJS 1.6.xo +:

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

bucket.upload(attachment, options);

Entonces, obtener la URL pública es tan simple como:

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

2
Eso de hecho parece funcionar. Sin embargo, el único inconveniente que veo hasta ahora es que si presiona la imagen en la barra de URL de un navegador, descargará la imagen en lugar de verla en línea.
Michael Giovanni Pumo

file.getMetadata () me hizo el truco después de usar el método save () en la referencia del archivo. Usándolo en NodeJS con firebase-admin sdk.
Pascal Lamers

no funcionó, recibo una llamada anónima que no tiene storage.objects.get acceso a your_app / image.jpg
Manoj MM

9

Lo siento, pero no puedo publicar un comentario a su pregunta anterior debido a la falta de reputación, por lo que la incluiré en esta respuesta.

Haga lo que se indicó anteriormente generando una URL firmada, pero en lugar de usar service-account.json, creo que debe usar serviceAccountKey.json que puede generar en (reemplace YOURPROJECTID en consecuencia)

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

Ejemplo:

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

9

No puedo comentar sobre la respuesta que dio James Daniels, pero creo que es muy importante leer esto.

Dar una URL firmada, como lo hizo él, parece en muchos casos bastante malo y posiblemente peligroso. . De acuerdo con la documentación de Firebase, la URL firmada caduca después de un tiempo, por lo que agregarla a su base de datos conducirá a una URL vacía después de un cierto período de tiempo.

Es posible que no se haya entendido bien la Documentación allí y que la URL firmada no caduque, lo que tendría algunos problemas de seguridad como resultado. La clave parece ser la misma para todos los archivos cargados. Esto significa que una vez que obtenga la URL de un archivo, alguien podría acceder fácilmente a los archivos a los que no se supone que acceda, simplemente conociendo sus nombres.

Si entendí mal eso, entonces me gustaría ser corregido. De lo contrario, probablemente alguien debería actualizar la solución mencionada anteriormente. Si puedo estar equivocado allí


7

Esto es lo que uso actualmente, es simple y funciona a la perfección.

No necesitas hacer nada con Google Cloud. Funciona de inmediato con 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

EDITAR: Mismo ejemplo, pero con carga:

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

actualizar:

no es necesario realizar dos llamadas diferentes en el método de carga para obtener los metadatos:

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

1
¿Cómo lo usaría con un archivo que no está codificado en base64?
Tibor Udvari

1
No es mediaLinkenter, es solo mediaLink
l2aelba

1
No puedo encontrar mediaLink i.stack.imgur.com/B4Fw5.png
sarah

@Sarah Escribí esto usando mecanografiado, no estoy seguro de si hay algún reemplazo de módulo.
Oliver Dixon

3

Tuve el mismo problema, sin embargo, estaba mirando el código del ejemplo de la función firebase en lugar del README. Y las respuestas en este hilo tampoco ayudaron ...

Puede evitar pasar el archivo de configuración haciendo lo siguiente:

Ve a tu proyecto Cloud Console de > IAM y administración> IAM , busque la cuenta de servicio predeterminada de App Engine y agregue la función Creador de tokens de la cuenta de servicio a ese miembro. Esto permitirá que su aplicación cree URL públicas firmadas para las imágenes.

fuente: función de automática de miniaturas README

Su función para el motor de aplicaciones debería verse así:

Consola en la nube


3

Si usa el valor de listas de control de acceso predefinido de 'publicRead', puede cargar el archivo y acceder a él con una estructura de URL muy simple:

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

Luego puede construir la URL así:

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

2

Esto funciona si solo necesita un archivo público con una URL simple. Tenga en cuenta que esto puede anular sus reglas de almacenamiento de Firebase.

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

1

Para aquellos que usan Firebase SDK y admin.initializeApp:

1 - Genere una clave privada y colóquela en la carpeta / functions.

2 - Configure su código de la siguiente manera:

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

Documentación

El intento / captura es porque estoy usando un index.js que importa otros archivos y crea una función para cada archivo. Si está utilizando un solo archivo index.js con todas las funciones, debería estar de acuerdo con admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.


para mí fue '../serviceaccountkey.json' pero gracias por los avisos para usar el ../
robert king

1

A partir de firebase 6.0.0, pude acceder al almacenamiento directamente con el administrador de esta manera:

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

Así que no necesité agregar una cuenta de servicio. Luego, configurar el UUID como se mencionó anteriormente funcionó para obtener la URL de la base de fuego.


1

Esto es lo mejor que se me ocurrió. Es redundante, pero la única solución razonable que funcionó para mí.

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

1

Sin signedURL()usarmakePublic()

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


0

Si recibe un error:

Funciones de Google Cloud: require (…) no es una función

prueba esto:

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

0

Ya publico mi ans ... en la siguiente URL donde puede obtener el código completo con la solución

¿Cómo subo una imagen (cadena) codificada en base64 directamente a un depósito de Google Cloud Storage con 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": "xxxx@xxxx.iam.gserviceaccount.com",
        "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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.