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

avatar
Valentin
22 марта 2017 в 15:35
110622
24
169

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

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

...

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

        // Get the download url of file

    });

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

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

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

Спасибо

Источник
Kato
14 июня 2017 в 19:16
0

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

Inzamam Malik
9 октября 2020 в 14:03
0

только если у вас нет правил безопасности firebase, то есть: разрешить чтение и запись при любых условиях, тогда этого шаблона будет достаточно "firebasestorage.googleapis.com/v0/b/… name>?alt=media"

Inzamam Malik
9 октября 2020 в 14:03
0

подписанный URL-адрес или токен требуется только в том случае, если у вас нет разрешения на чтение и запись, если auth имеет значение null

Ответы (24)

avatar
James Daniels
22 марта 2017 в 17:53
170

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

ОБНОВЛЕНИЕ. Доступ к Cloud Storage SDK теперь можно получить через Firebase Admin SDK, который выступает в качестве оболочки вокруг @google-cloud/storage. Единственный способ это сделать, если вы либо:

  1. Запустите SDK с помощью специальной учетной записи службы, обычно через второй экземпляр, отличный от используемого по умолчанию.
  2. Или, без учетной записи службы, предоставив учетной записи службы App Engine по умолчанию разрешение «signBlob».
Valentin
23 марта 2017 в 08:26
101

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

James Daniels
23 марта 2017 в 17:46
3

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

HowlingFantods
30 марта 2017 в 22:07
0

Ни в одном из документов Cloud Functions for Firebase не показана инициализация с такими учетными данными учетной записи службы: github.com/firebase/functions-samples/blob/master/quickstarts/… Однако, когда я пытаюсь без этого, я получаю «SigningError ' относительно отсутствующего ключевого файла. @ДжеймсДэниелс

James Daniels
1 апреля 2017 в 02:21
1

Верно, но ни в одном из документов не используется getSignedUrl, что я исправлю github.com/firebase/functions-samples/issues/82 Однако, по словам Като, мы делаем это в лаборатории кода.

Bogac
19 апреля 2017 в 16:29
24

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

David Aroesti
25 апреля 2017 в 18:20
3

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

TheeBen
22 октября 2017 в 18:28
0

Не будет ли небезопасно оставить файл serviceAccount.json в папке functions или где-нибудь в папке проекта?

Alexander Khitev
23 октября 2017 в 05:23
0

Скажите, пожалуйста, как я могу использовать среду firebase вместо файла json в этом случае?

Chad Bingham
20 июня 2018 в 16:40
2

Нужно ли добавлять action и expires?

Abdul Vajid
22 сентября 2018 в 10:32
1

@Alexander Александр - вам может понадобиться посмотреть Firebase.config для таких переменных среды.

raks
27 октября 2018 в 11:31
0

Я все еще получаю следующую ошибку. <Code>MalformedSecurityHeader</Code> <Message>Ваш запрос имеет неправильный заголовок.</Message> <ParameterName>signature</ParameterName> <Details>Подпись не была закодирована в base64</Details>

Kat
12 декабря 2018 в 15:37
1

Этот ответ обновлен лишь частично, что вызвало у меня много путаницы. Подробные инструкции о том, как это сделать из Firebase Admin SDK, см. в решении, опубликованном @SMX 07.11.18.

Dan Alboteanu
29 января 2019 в 19:12
0

Учетная запись службы, которую вы получаете из консоли Firebase, имеет роль «Редактор», у которой нет необходимых разрешений IAM. Для этого вам нужна такая роль, как «Создатель токена сервисной учетной записи». Проверьте groups.google.com/forum/#!topic/firebase-talk/-kxUMVPjQkk

Jaydip Kalkani
7 июня 2019 в 11:54
3

срок действия этого URL-адреса истекает через неделю? или это будет действительно до 03-09-2491? @Фрэнк ван Паффелен

Mayur Dhurpate
7 июля 2019 в 04:47
0

Я попытался запустить getSignedUrl, но сгенерированный URL-адрес показывает следующую ошибку: Your request has a malformed header. Signature was not base64 encoded Разместил сгенерированный URL-адрес, обходной путь и полную ошибку здесь: github.com/googleapis/google-cloud-go/issues/… Это баг или я что-то не так делаю?

Ryan Langton
6 августа 2019 в 21:37
2

Это решение возвращает безумно длинный URL-адрес, который не соответствует тому, что вы получаете, если вы зайдете в консоль firebase и нажмете получить URL-адрес загрузки. Это также не работает

Dody
18 марта 2020 в 15:03
3

Это не работает, я имею в виду только в течение 7 дней, есть ли простой способ получить загруженный URL без истечения срока действия?

maganap
13 апреля 2020 в 14:28
8

Остерегаться! Подписанные URL-адреса не предназначены для длительного использования, и срок их действия истекает максимум через 2 недели (v4). Если вы собираетесь хранить это в своей базе данных в течение длительного времени, подписанные URL-адреса не являются правильным способом. Проверьте свойство expires здесь: googleapis.dev/nodejs/storage/latest/…

Inzamam Malik
19 января 2021 в 12:59
0

Я нашел этот ответ полезным, и я попытался проголосовать и угадать, что :-) в сообщении об ошибке говорилось: «Последний раз вы голосовали за этот ответ 9 октября 2020 года в 14:03. Ваш голос теперь заблокирован, если этот ответ не отредактирован». Google действительно нужно упростить свои документы ради бога

Unknown2433
24 января 2022 в 15:31
0

Этот URL работает для длительного использования? Я проверил, и он работает до сих пор (5 дней). Я не уверен, будет ли это работать долго или нет.

avatar
Jaesung
31 декабря 2021 в 23:03
0

Использовать file.publicUrl()

Асинхронный/Ожидание

const bucket = storage.bucket('bucket-name');
const uploadResponse = await bucket.upload('image-name.jpg');
const downloadUrl = uploadResponse[0].publicUrl();

Обратный вызов

const bucket = storage.bucket('bucket-name');
bucket.upload('image-name.jpg', (err, file) => {
  if(!file) {
    throw err;
  }

  const downloadUrl = file.publicUrl();
})

downloadUrl будет "https://storage.googleapis.com/bucket-name/image-name.jpg".

Обратите внимание, что для того, чтобы приведенный выше код работал, вы должны сделать корзину или файл общедоступными. Для этого следуйте инструкциям здесь https://cloud.google.com/storage/docs/access-control/making-data-public. Кроме того, я импортировал пакет @google-cloud/storage напрямую, а не через Firebase SDK.

avatar
Chukwuemeka Maduekwe
9 ноября 2020 в 14:29
0

Я видел это в документе хранилища администратора

const options = {
  version: 'v4',
  action: 'read',
  expires: Date.now() + 15 * 60 * 1000, // 15 minutes
};

// Get a v4 signed URL for reading the file
const [url] = await storage
  .bucket(bucketName)
  .file(filename)
  .getSignedUrl(options);

console.log('Generated GET signed URL:');
console.log(url);
console.log('You can use this URL with any user agent, for example:');
console.log(`curl '${url}'`);
avatar
germands
10 сентября 2020 в 13:23
0

Для тех, кто пытается использовать параметр токена для совместного использования файла и хотел бы использовать команду gsutil, вот как я это сделал:

Сначала вам нужно пройти аутентификацию, выполнив: gcloud auth

Затем запустите:

gsutil setmeta -h "x-goog-meta-firebaseStorageDownloadTokens:$FILE_TOKEN" gs://$FIREBASE_REPO/$FILE_NAME

Затем вы можете скачать файл по следующей ссылке:

https://firebasestorage.googleapis.com/v0/b/$FIREBASE_REPO/o/$FILE_NAME?alt=media&token=$FILE_TOKEN

avatar
Jasdeep Singh
24 февраля 2020 в 11:56
2

ответ https://coderhelper.com/users/269447/laurent лучше всего работает

const uploadOptions: UploadOptions = {
    public: true
};

const bucket = admin.storage().bucket();
[ffile] = await bucket.upload(oPath, uploadOptions);
ffile.metadata.mediaLink // this is what you need
Damien Romito
4 февраля 2021 в 07:57
0

Если вы не заботитесь о безопасности, ЭТО более простое решение! Большое спасибо @Jasdeep. Я сделал const response = await upload.bucket(... ///// response[0]..metadata.mediaLink // это то, что вам нужно

avatar
Rawan-25
2 января 2020 в 06:23
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);
avatar
ersin-ertan
19 сентября 2019 в 18:08
2

Без 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);
        });
    });
});
avatar
Wild Goat
16 сентября 2019 в 23:22
-1

Если вы получаете сообщение об ошибке:

Облачные функции Google: 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);
.....
avatar
Thomas David Kehoe
6 мая 2019 в 18:00
116

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

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

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

.

Из консоли Firebase Storage

Вы можете получить URL-адрес загрузки из консоли Firebase Storage:

enter image description here

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 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 никогда не говорит, что срок действия вашего подписанного 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));
    });

Результат в браузере облачного хранилища будет выглядеть следующим образом:

enter image description here

Затем любой может использовать стандартный путь для загрузки вашего файла:

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

Другой способ сделать файл общедоступным — использовать метод makePublic(). Мне не удалось заставить это работать, сложно правильно указать путь к корзине и файлам.

Интересной альтернативой является использование списков контроля доступа. Вы можете сделать файл доступным только для пользователей, внесенных в список, или использовать authenticatedRead, чтобы сделать файл доступным для всех, кто вошел в систему из учетной записи Google. Если бы была опция «любой, кто вошел в мое приложение с помощью аутентификации Firebase», я бы использовал ее, так как это ограничило бы доступ только для моих пользователей.

Создайте собственный URL-адрес загрузки с помощью firebaseStorageDownloadTokens

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

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

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

Théo Champion
15 мая 2019 в 05:15
22

Для этого я создал задачу на @google-cloud/storage, не стесняйтесь +1;) github.com/googleapis/nodejs-storage/issues/697

galki
12 ноября 2019 в 10:13
1

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

Mason
18 ноября 2019 в 07:20
1

Кажется, firebaseStorageDownloadTokens больше не работает.

DevMike
20 ноября 2019 в 04:28
1

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

Nainal
5 декабря 2019 в 12:02
0

getDownloadURL() возвращает URL-адрес, доступный любому, и не требует аутентификации пользователя, поэтому он менее безопасен.

czphilip
7 февраля 2020 в 07:00
2

@thomas спасибо за отличное резюме! Вы упомянули, что существует 3 способа получить постоянный URL-адрес загрузки токена, но вы поделились только двумя: (а) из консоли хранилища Firebase и (б) getDownloadURL() из внешнего интерфейса. Интересно, что за 3-й способ?

E. Sun
11 апреля 2020 в 21:26
0

@czphilip Если вы хотите просто использовать общедоступный URL-адрес, вы можете сделать await admin.storage().bucket(object.bucket).file(object.name!).makePublic();, затем object.mediaLink, чтобы сделать этот файл общедоступным.

atereshkov
11 декабря 2020 в 11:38
0

Это очень очень полезная статья. Я потратил некоторое время на изучение и сбор информации из Google, и вы сэкономили мне кучу часов.

Andrew
21 июля 2021 в 06:50
0

в чем преимущество getDownloadUrl по сравнению с общедоступным объектом? Не может ли каждый получить доступ к каждой ссылке? Единственная выгода в том, что вы можете отозвать доступ?

Redneys
17 ноября 2021 в 23:15
0

У кого-нибудь есть понимание вопроса Андрея? Мне интересно то же самое: для общедоступного файла, почему бы просто не получить доступ к общему общедоступному URL-адресу (например, storage.googleapis.com/bucketName/fileName)?

avatar
Tibor Udvari
20 апреля 2019 в 15:23
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)
avatar
inorganik
25 января 2019 в 05:28
6

Если вы используете предопределенные списки управления доступом со значением '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);
avatar
Oliver Dixon
2 января 2019 в 15:04
18

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

Вам не нужно ничего делать с 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 = metatata[0].mediaLink

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

let file = await bucket.upload(fromFilePath, {destination: toFilePath});
const trimUrl = file[0].metatata.mediaLink
Tibor Udvari
20 апреля 2019 в 15:24
1

Как бы вы использовали его с файлом, который не закодирован в base64?

l2aelba
23 августа 2019 в 21:15
1

Это не mediaLinkenter, это просто mediaLink

sarah
2 июля 2020 в 02:44
1

Я не могу найти mediaLink i.stack.imgur.com/B4Fw5.png

Oliver Dixon
3 июля 2020 в 05:25
0

@Sarah Я написал это, используя машинописный текст, не уверен, есть ли замена модуля.

Alexa289
2 июля 2021 в 05:38
0

@OliverDixon у этого метода есть ограничение по времени? Я имею в виду, подписанный URL-адрес из принятого ответа выше действителен только в течение 7 дней. как насчет URL-адреса, сгенерированного с помощью этого mediaLink? более 7 дней?

charles-allen
18 августа 2021 в 06:48
0

Я думаю, что metatata должно быть metaData

avatar
SMX
7 ноября 2018 в 19:27
33

Если вы работаете над проектом 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. .
  3. Оставаясь в консоли API, перейдите в главное меню "IAM и администратор" -> "IAM"
  4. Нажмите «Изменить» для роли «Учетная запись службы App Engine по умолчанию»
  5. Нажмите "Добавить другую роль" и добавьте роль "Создатель токена сервисной учетной записи"
  6. Сохраните и подождите минуту, пока изменения вступят в силу

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

Kat
12 декабря 2018 в 15:29
0

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

Amit Bravo
14 февраля 2019 в 05:37
3

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

Thomas David Kehoe
25 апреля 2019 в 22:19
2

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

Manoj MM
9 июля 2019 в 05:20
0

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

Saifallak
20 июля 2019 в 16:02
0

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

Alisson Nunes
9 июля 2020 в 03:55
3

Я получаю сообщение об ошибке «Невозможно подписать данные без client_email». с помощью эмулятора

avatar
NickJ
5 ноября 2018 в 01:15
1

Начиная с firebase 6.0.0 я смог получить доступ к хранилищу напрямую через администратора следующим образом:

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

Поэтому мне не нужно было добавлять сервисный аккаунт. Затем установка UUID, как указано выше, работала для получения URL-адреса firebase.

avatar
TheFullResolution
24 октября 2018 в 13:41
3

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

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

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

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

Ваша роль для механизма приложения должна выглядеть следующим образом:

Cloud Console

avatar
Allan Poppe
18 мая 2018 в 19:02
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) {}

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

Проблема try/catch связана с тем, что я использую index.js, который импортирует другие файлы и создает по одной функции для каждого файла. Если вы используете один файл index.js со всеми функциями, у вас должно быть все в порядке с admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.

robert king
12 ноября 2018 в 12:34
0

для меня это было '../serviceaccountkey.json', но спасибо за внимание к использованию ../

Alexa289
3 ноября 2020 в 07:46
0

не могли бы вы помочь объяснить. как получить URL загрузки? я не вижу этого в вашем коде

avatar
Renji
30 апреля 2018 в 21:09
10

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

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

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

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

avatar
Demian S
18 апреля 2018 в 02:02
23

С недавними изменениями в функциях object response вы можете получить все необходимое, чтобы "сшить" воедино 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);
Dygerati
11 июля 2018 в 20:30
2

Вы имеете в виду ответ объекта от bucket.file().upload()? Я не получаю никаких свойств метаданных в ответных данных и не знаю, как получить эти firebaseStorageDownloadTokens.

Călin Darie
13 июля 2018 в 07:28
0

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

Laurent
2 августа 2018 в 13:39
4

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

Doug Stevenson
12 ноября 2018 в 06:09
3

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

Laurent
16 ноября 2018 в 20:01
1

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

Demian S
17 ноября 2018 в 03:14
0

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

jon_wu
28 апреля 2019 в 02:20
1

Хотя мне также не нравится идея сохранения жестко закодированного URL-адреса, @DougStevenson (Google) предположил, что URL-адрес в том же формате был разработан для сохранения в его ответе на coderhelper.com/questions/53055190/…. Кажется, что все текущие URL-адреса должны будут продолжать работать в течение некоторого времени, если люди сохранят их, но это не значит, что позже все не изменится. Я также обнаружил, что задержка с URL-адресами firebasestorage немного больше, чем с очень длинными подписанными.

Everett Glovier
8 апреля 2020 в 01:23
0

это отличный ответ, который я давно искал. Спасибо, что предоставили мне firebaseStorageDownloadTokens, Демиан С!

avatar
Laurent
21 марта 2018 в 16:03
29

В коде следует избегать жесткого кодирования префикса 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);
});
Pascal Lamers
16 декабря 2018 в 23:34
0

file.getMetadata() помог мне после использования метода save() для ссылки на файл. Использование его в NodeJS с firebase-admin sdk.

avatar
Dakine
14 января 2018 в 12:34
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);
    }
});
avatar
Drew Beaupre
3 мая 2017 в 15:46
111

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

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, вложенный в свойство option metadata. Если для firebaseStorageDownloadTokens задано значение uuid-v4, Cloud Storage будет использовать его в качестве общедоступного токена аутентификации.

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

DerFaizio
16 июня 2017 в 08:14
0

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

DerFaizio
16 июня 2017 в 10:02
3

Нашел ответ в посте @martemorphosis. UUID можно получить из object.metadata exports.uploadProfilePic = functions.storage.object().onChange(event => { const object = event.data; // Объект Storage. const uuid = object.metadata.firebaseStorageDownloadTokens; // ...

JCarlosR
29 августа 2017 в 18:34
0

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

Stanislau Buzunko
26 марта 2018 в 08:55
1

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

Michel
10 апреля 2019 в 08:32
0

Потрясающий! Я использовал ту же технику с клиентской библиотекой PHP GCS!

DevMike
20 ноября 2019 в 04:21
0

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

Samuel E.
20 ноября 2019 в 11:59
2

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

DevMike
20 ноября 2019 в 14:07
0

Я пробовал это ранее сегодня, и хотя сама загрузка прошла успешно, составление ссылки так, как вы описали, у меня не сработало, есть идеи? Я столкнулся с проблемами разрешений даже для аутентифицированных клиентов.

Andrew
21 июля 2021 в 06:47
0

какой смысл делать это, а не просто публиковать? Любой может использовать одну и ту же ссылку

Pete Shilling
17 ноября 2021 в 20:11
0

Я согласен, что это правильный ответ. Срок действия подписанных URL-адресов истекает, что является нарушением условий сделки. URL-адреса «mediaLink» не всегда работают правильно (нет заголовков кеша, ответ 206 на запросы диапазона байтов и т. д.). Этот метод идеально имитирует метод getDownloadURL клиентского хранилища, а это именно то, что я хотел.

Redneys
17 ноября 2021 в 23:06
0

Есть ли причина использовать этот подход для общедоступного файла вместо того, чтобы просто сделать корзину Cloud Storage общедоступной и получить доступ к общему общедоступному URL-адресу (например, storage.googleapis.com/bucketName/fileName)?

avatar
Clinton
26 апреля 2017 в 15:00
19

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

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

avatar
martemorfosis
3 апреля 2017 в 23:15
19

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

Drew Beaupre
2 мая 2017 в 03:32
1

У вас есть пример, где вы устанавливаете значение uuid?

Vysakh Sreenivasan
3 мая 2017 в 11:47
1

У меня тот же вопрос, что и у Дрю, где вы устанавливаете метаданные? Я пытался установить функциюbucket.upload, но это не сработало.

Drew Beaupre
3 мая 2017 в 15:47
1

Висах, я разместил полный ответ с примером. Надеюсь, это поможет вам.

CodyBugstein
20 июля 2018 в 03:01
0

Где/как вы создаете токен?

Doug Stevenson
17 сентября 2018 в 04:49
5

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

avatar
NiVeK92
23 марта 2017 в 09:36
11

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

Сделайте, как указано выше, сгенерировав подписанный 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 
        })