Отримайте URL-адресу завантаження з файлу, завантаженого за допомогою хмарних функцій для Firebase


124

Після завантаження файлу в Firebase Storage з функціями для Firebase я хотів би отримати URL-адресу завантаження файлу.

У мене це:

...

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

        // Get the download url of file

    });

Об'єктний файл має безліч параметрів. Навіть одна названа mediaLink. Однак якщо я спробую отримати доступ до цього посилання, я отримаю цю помилку:

Анонімні користувачі не мають доступу до об’єкта storage.objects.get ...

Хтось може сказати мені, як отримати загальну URL-адресу для завантаження?

Дякую


Дивіться також цю публікацію, яка реконструює URL із даних, доступних у функції.
Като

Відповіді:


133

Вам потрібно буде генерувати підписану URL-адресу за допомогою getSignedURL через модуль @ google-cloud / storage NPM.

Приклад:

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

Вам потрібно буде ініціалізуватися @google-cloud/storageз обліковими записами вашого облікового запису послуги, оскільки облікові дані програми за замовчуванням будуть недостатніми.

ОНОВЛЕННЯ : До SDK хмарного зберігання тепер можна отримати доступ через пакет SDK Firebase Admin, який виконує функцію обгортки навколо @ google-cloud / storage. Єдиний спосіб, як це:

  1. Запустіть SDK за допомогою спеціального облікового запису служби, як правило, через другий екземпляр, який не використовується за замовчуванням.
  2. Або без облікового запису служби, надавши дозволу "signBlob" за замовчуванням облікового запису служби App Engine.

74
Це дивно. Ми можемо легко отримати URL-адресу завантаження з посилання на сховище при використанні Firebase Android, iOS та Web SDK. Чому під час перебування в адміністраторі це не так просто? PS: Де я можу знайти "service-account.json", необхідний для ініціалізації gcs?
Валентин

2
Це пов’язано з тим, що в адмін-sdk немає жодних додатків Cloud Storage. Ви можете отримати свій обліковий запис адміністратора sdk json тут console.firebase.google.com/project/_/settings/serviceaccounts/…
Джеймс Даніельс

18
URL-адреса, створена цим методом, смішно довга. URL-адреса, створена запропонованим методом @martemorfosis, значно краща. Чи є якась функція, яка виробляє цю URL-адресу? Це те, що я зберігаю в базі даних для подальшого використання, коли я використовую firebase-sdk. Дзеркальний метод повинен існувати в області функцій.
Богач

3
Як ми можемо завантажити сервіс-account.json вздовж розгорнутих функцій? Я спробував розмістити його в папці з функціями та посилатись на нього у поле файлу в package.json, але він не розгортається. Дякую.
Девід Арості

2
Нам потрібно додати actionі expires?
Чад Бінгем

82

Ось приклад того, як вказати маркер завантаження для завантаження:

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

потім дзвоніть з

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

Ключовим тут є те, що в властивості параметра є metadataвкладений об'єкт metadata. Встановлення firebaseStorageDownloadTokensзначення uuid-v4 скаже Cloud Storage використовувати його як свій публічний маркер аутентифікації.

Велике спасибі @martemorfosis


Як отримати дійсний маркер UUID для файлу, який уже завантажено в Storage? Генерування випадкових UUID не допомогло. Якісь покажчики?
DerFaizio

3
Знайшов відповідь у публікації @martemorfosis. UUID можна отримати з object.metadata export.uploadProfilePic = функции.storage.object (). OnChange (event => {const object = event.data; // Об'єкт зберігання. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio

Дякую за приклад відра! Я майже 1 годину намагався використовувати різні комбінації методів відра та файлів :)
JCarlosR

1
Дякую за вашу відповідь! У моєму випадку я завантажував за допомогою bucket.file (fileName) .createWriteStream, який не повертає дані, коли закінчує завантаження, в результаті я використовував encodeURIComponent (fileName) замість encodeURIComponent (file.name).
Станіслав Бузунко

2
Це має бути правильна відповідь. Це призводить до отримання URL-адреси, подібної до тієї, яку генерують SDK Firebase (@DevMike), і я ставлю на облік саме те, що вони роблять за кадром.
Самуель Е.

64

Ця відповідь підсумовує варіанти отримання URL-адреси для завантаження під час завантаження файлу в Google / Firebase Cloud Storage. Існує три типи URL-адрес для завантаження:

  1. URL-адреси для завантаження з підписом, які є тимчасовими та мають функції захисту
  2. URL-адреси для завантаження маркера, які є стійкими та мають функції захисту
  3. публічні URL-адреси для завантаження, які є стійкими і не мають захисту

Існує три способи отримати URL-адресу для завантаження маркера. Інші два URL-адреси для завантаження мають лише один спосіб їх отримання.

З консолі зберігання Firebase

Ви можете отримати URL-адресу для завантаження з консолі Firebase Storage:

введіть тут опис зображення

URL-адреса для завантаження виглядає приблизно так:

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

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

getDownloadURL () З переднього кінця

Документація говорить нам використовувати getDownloadURL():

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

Це отримує ту саму URL-адресу для завантаження, яку ви можете отримати з консолі Firebase Storage. Цей спосіб простий, але вимагає знати шлях до вашого файлу, який у моєму додатку становить близько 300 рядків коду, для відносно простої структури бази даних. Якщо ваша база даних складна, це був би кошмар. І ви можете завантажувати файли з переднього кінця, але це відкриє ваші облікові дані кожному, хто завантажує вашу програму. Тож для більшості проектів ви хочете завантажити свої файли із заднього кінця вузла чи Google Cloud Functions, а потім отримати URL-адресу для завантаження та зберегти її у вашу базу даних разом з іншими даними про ваш файл.

getSignedUrl () для тимчасових URL-адрес завантаження

getSignedUrl () простий у використанні із заднього кінця вузла чи функцій Google Cloud:

  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-адреса для завантаження виглядає приблизно так:

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-адреса має термін дії та довгий підпис. У документації до командного рядка gsutil signurl -d сказано, що підписані URL-адреси є тимчасовими: термін дії за замовчуванням становить одну годину, а максимальний термін дії - сім днів.

Я збираюся тут розігнати, що getSignedUrl ніколи не каже, що термін дії вашої підписаної дати закінчиться через тиждень. Код документації має 3-17-2025дату закінчення терміну придатності, що передбачає, що ви можете встановити роки закінчення терміну придатності в майбутньому. Мій додаток працював ідеально, а потім вийшов з ладу через тиждень. У повідомленні про помилку вказується, що підписи не збігаються, а не те, що термін дії URL-адреси для завантаження минув. Я вносив різні зміни до свого коду, і все працювало ... доти, як усе через тиждень все не вийшло з ладу. Це тривало понад місяць розчарування.

Зробіть свій файл загальнодоступним

Ви можете встановити дозволи на ваш файл для публічного читання, як це пояснено в документації . Це можна зробити з браузера хмарного зберігання даних або з вашого сервера вузлів. Ви можете зробити один файл загальнодоступним, каталог чи всю базу даних. Ось код Вузла:

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

Результат виглядатиме так у вашому браузері хмарного зберігання:

введіть тут опис зображення

Потім кожен може скористатися стандартним шляхом для завантаження вашого файлу:

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

Інший спосіб оприлюднити файл - це використовувати метод makePublic () . Мені не вдалося змусити це працювати, складно правильно виправити шляхи відра та файлу.

Цікавою альтернативою є використання списків контролю доступу . Ви можете зробити файл доступним лише для користувачів, яких ви внесли до списку, або використовувати його, authenticatedReadщоб зробити його доступним для всіх, хто ввійшов з облікового запису Google. Якби була опція "кожен, хто ввійшов у мій додаток за допомогою Firebase Auth", я б застосував це, оскільки це обмежило б доступ лише до моїх користувачів.

Створіть власну URL-адресу завантаження за допомогою firebaseStorageDownloadTokens

Кілька відповідей описують недокументовану властивість об’єкта Google Storage firebaseStorageDownloadTokens. За допомогою цього ви можете сказати Storage маркер, який ви хочете використовувати. Ви можете генерувати маркер за допомогою uuidмодуля "Вузол". Чотири рядки коду, і ви можете створити власну URL-адресу для завантаження, ту ж URL-адресу для завантаження, яку ви отримаєте з консолі або getDownloadURL(). Чотири рядки коду:

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

Ось код у контексті:

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

Це не помилка - ви повинні гніздитися firebaseStorageDownloadTokensв подвійних шарах metadata:!

Дуг Стівенсон зазначив, що firebaseStorageDownloadTokensце не офіційна функція зберігання в хмарі Google. Ви не знайдете його в жодній документації Google, і не обіцяйте, що вона буде в майбутній версії @google-cloud. Мені подобається, firebaseStorageDownloadTokensтому що це єдиний спосіб отримати те, що я хочу, але він має «запах», який використовувати його не безпечно.

Чому немає getDownloadURL () від Node?

Як писав @Clinton, Google повинен створити file.getDownloadURL()метод у @google-cloud/storage(тобто зворотній частині вашого вузла). Я хочу завантажити файл з Google Cloud Functions і отримати URL-адресу для завантаження маркера.


10
Я створив проблему з @google-cloud/storageцього приводу, не соромтеся поставити +1;) github.com/googleapis/nodejs-storage/isissue/697
Чемпіон Тео

1
останнє посилання makePublic ()
galki

1
Здається, firebaseStorageDownloadTokensбільше не працює.
Мейсон

1
Прийнята відповідь говорить про те, що неможливо отримати стійкий URL-адресу завантаження, який не закінчується, що невірно. Деталі у вашій відповіді є чудовими і повинні бути позначені як правильна відповідь. Дякую.
DevMike

2
@thomas дякую за приголомшливий підсумок! Ви згадали, що існує три способи отримати постійну URL-адресу для завантаження маркера, але ви поділилися лише 2: (a) з консолі зберігання Firebase та (b) getDownloadURL () з переднього кінця. Цікаво, що таке 3-й спосіб?
czphilip

23

Завдяки останнім змінам у відповіді об'єкта функцій ви можете отримати все необхідне для "зшивання" разом URL-адреси для завантаження так:

 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
Ви посилаєтесь на відповідь об'єкта від bucket.file().upload()? Я не отримую жодних властивостей метаданих у даних відповідей, і я не знаю, як їх отримати firebaseStorageDownloadTokens.
Дігерати

також [ВАШ БУКЕТ] є bucket.name, вам не доведеться жорстко кодувати його або використовувати додатковий локальний вар
Călin Darie

4
Проблема цього рішення полягає в тому, що URL-адреса служби жорстко кодована. Якщо Firebase / Google змінить її, вона може зламатися. Використання metadata.mediaLinkвластивості запобігає такій проблемі.
Лоран

2
Для створення такої URL-адреси не підтримується випадок. Це може працювати сьогодні, але може зламатися в майбутньому. Вам слід використовувати лише надані API, щоб створити належну URL-адресу для завантаження.
Дуг Стівенсон

1
Покладатися на жорстко закодовану URL-адресу, яка може змінитися - це поганий вибір.
Лоран

23

Якщо ви працюєте над проектом Firebase, ви можете створювати підписані URL-адреси у хмарній функції, не включаючи інші бібліотеки та не завантажуючи файл облікових даних. Вам просто потрібно ввімкнути API IAM та додати роль до наявного облікового запису послуги (див. Нижче).

Ініціалізуйте бібліотеку адміністратора та отримайте посилання на файл, як зазвичай:

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

Потім ви генеруєте підписану URL-адресу за допомогою

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

Переконайтеся, що ваш обліковий запис служби Firebase має достатньо дозволів для його запуску

  1. Перейдіть на консоль API Google і ввімкніть API IAM ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )
  2. Ще в консолі API перейдіть до головного меню "IAM & admin" -> "IAM"
  3. Клацніть редагувати для ролі "Обліковий запис служби за замовчуванням App Engine"
  4. Клацніть "Додати ще одну роль" та додайте ту, що називається "Творець жетонів облікового запису служби"
  5. Збережіть і почекайте хвилину, щоб зміни розповсюдилися

За допомогою конфігурації Firefox Firefox під час першого запуску вищевказаного коду ви отримаєте API помилки ідентифікації та управління доступом (IAM), який не використовувався в проекті XXXXXX раніше, або він відключений. . Якщо ви перейдете за посиланням у повідомленні про помилку та ввімкнете API IAM, ви отримаєте ще одну помилку: для виконання цієї операції на обліковому записі служби my-service потрібно мати дозвіл iam.serviceAccounts.signBlob . Додавання ролі Token Creator виправляє цю другу проблему з дозволом.


Я ось-ось збирався залишити відповідь в основному на ті самі деталі, які я НАРЕШЧО вирішив важким шляхом - впевнене бажання, що я прочитав рішення набагато раніше: / Це працювало для мене станом на 12.12.18. Дякую за детальну інструкцію, дуже корисна для нас початківців !!
Кет

2
Мій підпис закінчується через 2 тижні, але я використовую адмін.initializeApp () без ключа, це проблема? У мене в обліковому записі служби за замовчуванням для додатка App Engine було встановлено "власник" та агент агента хмарних функцій. Я просто видалив "власника" наразі і додав "Творець
Аміт Браво

2
Підписані URL-адреси закінчуються через 7 днів. Ви можете встановити коротший термін придатності, але не довший.
Томас Девід Кехо,

Як оновити URL, якщо термін його дії закінчився?
Manoj MM

як оновити URL, щоб встановити його на довший час?
Сайфаллак

17

Один із методів, які я успішно використовую, - це встановити значення UUID v4 для ключа, названого firebaseStorageDownloadTokensв метаданих файлу після того, як він закінчує завантаження, а потім самостійно зібрати URL-адресу завантаження за структурою, яку Firebase використовує для створення цих URL-адрес, наприклад:

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

Я не знаю, наскільки "безпечним" є використання цього методу (враховуючи, що Firebase може змінити спосіб генерування URL-адрес для завантаження в майбутньому), але це легко здійснити.


1
Чи є у вас приклад, коли ви встановлюєте значення uuid?
Дрю Бопре

1
У мене те саме питання, що і Дрю, де ви встановлюєте метадані? Я намагався встановити функцію bucket.upload, але не вийшло.
Висах Сріенівасан

1
Висах, я розмістив повну відповідь w / приклад. Сподіваюся, що вам допоможе.
Дрю Бопре

Де / як ви створюєте маркер?
CodyBugstein

3
Я б не вважав цю методику "безпечною", оскільки URL-адреси для завантаження мають бути непрозорими, компоненти яких не повинні бути розбиті або зібрані.
Дуг Стівенсон

16

Для тих, хто цікавиться, куди має піти файл Firebase Admin SDK serviceAccountKey.json. Просто помістіть його в папку з функціями та розгорніть як завжди.

Це все ще бентежить мене, чому ми не можемо просто отримати URL-адресу завантаження з метаданих, як це робимо в SDK Javascript. Генерування URL-адреси, який з часом закінчиться, та збереження його в базі даних не бажано.


15

Я пропоную використовувати опцію predefinedAcl: 'publicRead'під час завантаження файлу за допомогою Cloud Storage NodeJS 1.6.x або +:

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

bucket.upload(attachment, options);

Тоді отримати публічну URL-адресу так само просто:

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
Це насправді, здається, працює. Єдиним недоліком, який я зараз бачу, є те, що якщо ви потрапили на зображення в URL-адресі браузера, він завантажить зображення замість того, щоб переглядати його в рядку.
Майкл Джованні Пумо

file.getMetadata () зробив для мене трюк після використання методу save () у довідці про файл. Використовуючи його в NodeJS з firebase-admin sdk.
Паскаль Ламерс

не працював, я отримую анонімний абонент не має storage.objects.get доступ до your_app / image.jpg
Manoj MM

9

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

Зробіть, як зазначено вище, створивши підписаний URL, але замість того, щоб скористатися службою-account.json, я думаю, що вам доведеться використовувати serviceAccountKey.json, який ви можете створити (замініть YOURPROJECTID)

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

Приклад:

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

Я не можу коментувати відповідь, яку дав Джеймс Деніелс, але думаю, що це дуже важливо прочитати.

Видача підписаної URL-адреси Начебто він здається для багатьох випадків досить поганим та можливим небезпечним . Відповідно до документації Firebase, підписаний URL закінчується через деякий час, тому додавання, що до вашої бази даних призведе до порожнього URL через певний часовий проміжок часу

Можливо, неправильно зрозуміла там Документація, і підписаний URL не закінчується, що призведе до певних проблем із безпекою. Ключ, схоже, однаковий для кожного завантаженого файлу. Це означає, що коли ви отримали URL-адресу одного файлу, хтось може легко отримати доступ до файлів, до яких він не має доступу, просто знаючи їх імена.

Якби я неправильно зрозумів, що тоді я б хотів виправитись. Інакше хтось, ймовірно, повинен оновити вищезазначене рішення. Якщо я можу помилитися там


7

Це те, що я зараз використовую, це просто і працює бездоганно.

Вам не потрібно нічого робити з Google Cloud. Це працює з коробки з 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: Той самий приклад, але із завантаженням:

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

оновлення:

не потрібно робити два різних виклику в способі завантаження, щоб отримати метадані:

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

1
Як би ви використовували його з файлом, який не закодований base64?
Тібор Удварі

1
Це не mediaLinkenter, його просто mediaLink
l2aelba

1
Я не можу знайти mediaLink i.stack.imgur.com/B4Fw5.png
sarah

@Sarah Я написав це за допомогою typecript, не впевнений, чи є заміна модуля.
Олівер Діксон

3

У мене був той самий випуск, проте я дивився на код прикладу функції firebase замість README. І відповіді на цю тему також не допомогли ...

Ви можете уникнути передачі конфігураційного файлу, виконавши такі дії:

Перейдіть до хмарної консолі вашого проекту > IAM та адміністратор> IAM , знайдіть обліковий запис служби за замовчуванням служби App Engine і додайте до цього члена роль службового маркера облікових записів послуг. Це дозволить вашій програмі створювати підписані загальнодоступні URL-адреси для зображень.

джерело: Автоматично генерувати мініатюри функцією README

Ваша роль для двигуна додатків повинна виглядати так:

Хмарна консоль


3

Якщо ви використовуєте заздалегідь визначене значення списку контролю доступу "publicRead", ви можете завантажити файл та отримати доступ до нього за допомогою дуже простої структури URL:

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

Потім ви можете сконструювати URL так:

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

2

Це працює, якщо вам просто потрібен загальнодоступний файл з простою URL-адресою. Зауважте, що це може скасувати ваші правила зберігання 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

Для тих, хто використовує Firebase SDK та admin.initializeApp:

1 - Створіть приватний ключ і помістіть у папку / функції.

2 - Налаштуйте свій код наступним чином:

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

Документація

Спроба / улов полягає в тому, що я використовую index.js, який імпортує інші файли та створює одну функцію для кожного файлу. Якщо ви використовуєте один файл index.js з усіма функціями, вам слід добре admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.


для мене це було "../serviceaccountkey.json", але дякую за голову, щоб використовувати ../
король Роберт

1

Станом на firebase 6.0.0 я зміг отримати доступ до сховища безпосередньо з адміністратором так:

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

Тому мені не потрібно було додавати обліковий запис служби. Потім встановлення UUID як зазначено вище, працювало для отримання URL-адреси firebase.


1

Це найкраще, що я придумав. Це зайве, але єдине розумне рішення, яке працювало для мене.

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

Без signedURL()використанняmakePublic()

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

Якщо ви отримуєте помилку:

Функції Google Cloud: вимагати (…) не є функцією

спробуйте це:

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

Я вже розміщую свої ан ... у нижній URL-адресі, де ви можете отримати повний код з рішенням

Як я можу завантажувати базове зображення 64 (рядок) безпосередньо у відро для зберігання хмарних даних Google за допомогою 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.