Получить URL-адрес загрузки из файла, загруженного с помощью облачных функций для Firebase


125

После загрузки файла в хранилище Firebase с функциями для Firebase я хотел бы получить URL-адрес загрузки файла.

У меня есть это :

...

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

        // Get the download url of file

    });

В объектном файле много параметров. Даже по имени mediaLink. Однако, если я попытаюсь получить доступ к этой ссылке, я получаю такую ​​ошибку:

Анонимные пользователи не имеют доступа к объекту storage.objects.get ...

Может кто-нибудь сказать мне, как получить общедоступный URL для загрузки?

Спасибо


См. Также этот пост, который восстанавливает URL-адрес из данных, доступных в функции.
Kato

Ответы:


133

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

Пример:

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, который действует как оболочка для @ google-cloud / storage. Единственный способ - это если вы:

  1. Инициируйте SDK со специальной учетной записью службы, обычно через второй, нестандартный экземпляр.
  2. Или, без учетной записи службы, предоставив учетной записи службы App Engine по умолчанию разрешение «signBlob».

75
Это странно. Мы можем легко получить URL-адрес загрузки из ссылки на хранилище при использовании Firebase Android, iOS и веб-SDK. Почему в админке это не так просто? PS: Где я могу найти «service-account.json», необходимый для инициализации gcs?
Валентин

2
Это потому, что admin-sdk не имеет дополнений к облачному хранилищу. Вы можете получить свою учетную запись json службы admin-sdk здесь console.firebase.google.com/project/_/settings/serviceaccounts/…
Джеймс Дэниэлс,

18
URL-адрес, созданный с помощью этого метода, смехотворно длинный. URL, сгенерированный @martemorfosis, намного лучше. Есть ли какая-нибудь функция, которая производит этот URL? Это то, что я сохраняю в базе данных для будущего использования, когда использую firebase-sdk. Зеркальный метод должен существовать в домене функций.
Bogac

3
Как мы можем загрузить service-account.json вместе с развернутыми функциями? Я попытался поместить его в папку функций и сослаться на него в поле файла в package.json, но он не развертывается. Спасибо.
Дэвид Ароэсти

2
Обязательно ли добавлять actionи expires?
Chad Bingham

83

Вот пример того, как указать токен загрузки при загрузке:

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свойство option. Установка значения firebaseStorageDownloadTokensuuid-v4 укажет облачному хранилищу использовать его в качестве общедоступного токена аутентификации.

Большое спасибо @martemorfosis


Как получить действительный токен UUID для файла, который уже загружен в хранилище? Генерация случайного UUID не помогла. Есть указатели?
DerFaizio

3
Нашел ответ в сообщении @martemorfosis. UUID можно получить из объекта .metadata exports.uploadProfilePic = functions.storage.object (). OnChange (event => {const object = event.data; // Объект хранилища. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio

Спасибо за пример ведра! Я пробовал разные комбинации методов bucket и file почти 1 час :)
JCarlosR

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

2
Это должен быть правильный ответ. В результате получается URL, аналогичный тому, который создается SDK Firebase (@DevMike), и я уверен, что это именно то, что они делают за кулисами.
Samuel E.

66

В этом ответе будут обобщены варианты получения URL-адреса загрузки при загрузке файла в Google / Firebase Cloud Storage. Существует три типа URL-адресов для загрузки:

  1. подписанные URL-адреса загрузки, которые являются временными и имеют функции безопасности
  2. URL-адреса загрузки токенов, которые являются постоянными и имеют функции безопасности
  3. общедоступные URL-адреса загрузки, которые являются постоянными и не защищенными

Есть три способа получить URL для загрузки токена. Два других URL-адреса загрузки имеют только один способ получить их.

Из консоли Firebase Storage

Вы можете получить 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 строк кода для относительно простой структуры базы данных. Если ваша база данных сложна, это будет кошмар. И вы можете загружать файлы из внешнего интерфейса, но это сделает ваши учетные данные доступными для всех, кто скачивает ваше приложение. Таким образом, для большинства проектов вы захотите загрузить файлы из серверной части Node или из облачных функций Google, а затем получить URL-адрес загрузки и сохранить его в своей базе данных вместе с другими данными о вашем файле.

getSignedUrl () для временных URL-адресов загрузки

getSignedUrl () легко использовать из серверной части Node или из облачных функций Google:

  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 никогда не говорит, что срок действия вашего подписанного URL истечет через неделю. В коде документации 3-17-2025указана дата истечения срока действия, что означает, что вы можете установить годы истечения срока действия в будущем. Мое приложение работало отлично, а через неделю вылетело. В сообщении об ошибке говорилось, что подписи не совпадают, а не о том, что срок действия URL-адреса загрузки истек. Я внес различные изменения в свой код, и все работало ... пока через неделю все не рухнуло. Это продолжалось более месяца разочарования.

Сделайте свой файл общедоступным

Вы можете установить разрешения для публичного чтения вашего файла, как описано в документации . Это можно сделать из браузера облачного хранилища или с вашего сервера Node. Вы можете сделать один файл общедоступным, каталог или всю базу данных Storage. Вот код узла:

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модуля Node. Четыре строки кода, и вы можете создать свой собственный 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 Cloud Storage. Вы не найдете его ни в одной документации Google, и нет никаких обещаний, что он будет в будущей версии @google-cloud. Мне нравится, firebaseStorageDownloadTokensпотому что это единственный способ получить то, что я хочу, но он имеет "запах", который небезопасно использовать.

Почему нет getDownloadURL () из узла?

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


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

1
последняя ссылка makePublic () .
galki

1
Вроде firebaseStorageDownloadTokensбольше не работает.
Мейсон

1
Принятый ответ предполагает, что невозможно получить постоянный URL-адрес загрузки, срок действия которого не истекает, что неверно. Подробности здесь в вашем ответе превосходны и должны быть отмечены как правильный ответ. Спасибо.
DevMike

2
@thomas, спасибо за потрясающее резюме! Вы упомянули, что есть 3 способа получить постоянный URL для загрузки токена, но вы поделились только двумя: (а) из консоли хранилища Firebase и (б) 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.
Dygerati

также [ВАШЕ ВЕДРО] bucket.name, вам не нужно жестко его кодировать или использовать дополнительную локальную
переменную

4
Проблема с этим решением заключается в том, что URL-адрес службы жестко запрограммирован. Если Firebase / Google изменит его, он может сломаться. Использование metadata.mediaLinkсвойства предотвращает такую ​​проблему.
Лоран

2
Создание такого URL-адреса не поддерживается. Это может работать сегодня, но может сломаться в будущем. Вы должны использовать только предоставленные API для создания правильного URL для загрузки.
Дуг Стивенсон

1
Использование жестко заданного URL-адреса, который может измениться, - плохой выбор.
Laurent

23

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

Инициализируйте библиотеку администратора и получите ссылку на файл, как обычно:

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. Перейдите в консоль Google API и включите IAM API ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )
  2. По-прежнему в консоли API перейдите в главное меню «IAM и администратор» -> «IAM».
  3. Нажмите "Изменить" для роли "Сервисный аккаунт App Engine по умолчанию".
  4. Нажмите «Добавить другую роль» и добавьте роль «Создатель токена учетной записи службы».
  5. Сохраните и подождите, пока изменения вступят в силу

С ванильной конфигурацией Firebase при первом запуске вышеуказанного кода вы получите сообщение об ошибке. API управления идентификацией и доступом (IAM) ранее не использовался в проекте XXXXXX или отключен. . Если вы перейдете по ссылке в сообщении об ошибке и включите IAM API, вы получите еще одну ошибку: Разрешение iam.serviceAccounts.signBlob требуется для выполнения этой операции в сервисной учетной записи my-service-account . Добавление роли Token Creator устраняет эту вторую проблему с разрешениями.


Я как раз собирался оставить ответ в основном с теми же деталями, которые я НАКОНЕЦ выяснил на собственном горьком опыте - конечно, жаль, что я не прочитал решения так далеко раньше: / Это сработало для меня по состоянию на 12/12/18. Спасибо за подробные инструкции, очень полезные для нас новичков !!
Кэт

2
Срок действия моего подписанного URL-адреса истекает через 2 недели, но я использую admin.initializeApp () без ключа, это проблема? У меня была учетная запись службы по умолчанию для приложения App Engine, настроенная на «владелец» и агент службы облачных функций, я просто удалил «владелец» и добавил «Создатель токена служебной учетной записи»
Амит Браво,

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

Как обновить URL-адрес, если срок его действия истек?
Manoj MM

как обновить URL-адрес, чтобы установить его на более длительное время?
Saifallak

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
Высах, я выложил полный ответ с примером. Надеюсь, это вам поможет.
Дрю Бопре

Где / как создать токен?
CodyBugstein

3
Я бы не стал считать эту технику «безопасной», так как URL-адреса загрузки должны быть непрозрачными, а их компоненты не должны разбираться или собираться.
Дуг Стивенсон

16

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

Меня все еще сбивает с толку, почему мы не можем просто получить URL-адрес загрузки из метаданных, как мы это делаем в Javascript SDK. Создание URL-адреса, срок действия которого в конечном итоге истечет, и сохранение его в базе данных нежелательно.


16

Вам следует избегать кодирования префикса URL в вашем коде . Я предлагаю использовать опцию 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
MM

9

Извините, но я не могу опубликовать комментарий к вашему вопросу выше из-за отсутствия репутации, поэтому я включу его в этот ответ.

Сделайте, как указано выше, создав подписанный URL-адрес, но вместо использования service-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-адрес одного файла, кто-то сможет легко получить доступ к файлам, к которым он не имеет доступа, просто зная их имена.

Если я неправильно это понял, то меня поправят. Еще кто-то, вероятно, должен обновить вышеуказанное решение. Если я могу ошибаться


8

Это то, что я использую сейчас, это просто и работает безупречно.

Вам не нужно ничего делать с 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

РЕДАКТИРОВАТЬ: тот же пример, но с загрузкой:

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

#update: нет необходимости выполнять два разных вызова метода загрузки для получения метаданных:

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 Я написал это с помощью машинописного текста, не уверен, есть ли замена модуля.
Оливер Диксон,

4

Если вы используете предопределенное значение списков управления доступом 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);

3

У меня была такая же проблема, однако я смотрел код примера функции firebase вместо README. И ответы в этой теме тоже не помогли ...

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

Перейдите в облачную консоль проекта > IAM и администратор> IAM , найдите учетную запись службы App Engine по умолчанию и добавьте этому участнику роль создателя токена учетной записи службы. Это позволит вашему приложению создавать подписанные общедоступные URL-адреса для изображений.

источник: функция автоматического создания эскизов README

Ваша роль в движке приложения должна выглядеть так:

Облачная консоль


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 - Создайте закрытый ключ и поместите его в папку / functions.

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 Functions: require (…) не является функцией

попробуй это:

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-адресе ниже, где вы можете получить полный код с решением

Как загрузить изображение (строку) в кодировке base64 непосредственно в корзину Google Cloud Storage с помощью 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.