Nhận URL tải xuống từ tệp được tải lên bằng Chức năng đám mây cho Firebase


124

Sau khi tải lên tệp trong Bộ lưu trữ Firebase với các chức năng cho Firebase, tôi muốn lấy url tải xuống của tệp.

Tôi có cái này:

...

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

        // Get the download url of file

    });

Tệp đối tượng có rất nhiều tham số. Ngay cả một cái tên mediaLink. Tuy nhiên, nếu tôi cố gắng truy cập liên kết này, tôi gặp lỗi này:

Người dùng ẩn danh không có quyền truy cập vào đối tượng storage.objects.get ...

Ai đó có thể cho tôi biết cách lấy Url tải xuống công khai không?

Cảm ơn bạn


Xem thêm bài đăng này tái tạo lại URL từ dữ liệu có sẵn trong hàm.
Kato

Câu trả lời:


133

Bạn sẽ cần tạo URL đã ký bằng getSignedURL thông qua mô-đun NPM @ google-cloud / storage .

Thí dụ:

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

Bạn sẽ cần khởi tạo @google-cloud/storagebằng thông tin đăng nhập tài khoản dịch vụ của mình vì thông tin đăng nhập mặc định của ứng dụng sẽ không đủ.

CẬP NHẬT : SDK lưu trữ đám mây hiện có thể được truy cập thông qua SDK quản trị viên Firebase, hoạt động như một trình bao bọc xung quanh @ google-cloud / storage. Cách duy nhất sẽ là nếu bạn:

  1. Kết hợp SDK với một tài khoản dịch vụ đặc biệt, thường thông qua phiên bản thứ hai, không phải là phiên bản mặc định.
  2. Hoặc, không có tài khoản dịch vụ, bằng cách cấp cho tài khoản dịch vụ App Engine mặc định quyền "signBlob".

74
Điều này thật kỳ lạ. Chúng tôi có thể dễ dàng lấy Url tải xuống từ tham chiếu Bộ nhớ khi sử dụng Firebase Android, iOS và SDK web. Tại sao nó không dễ dàng như trong quản trị? Tái bút: Tôi có thể tìm thấy 'service-account.json' cần thiết để khởi tạo gcs ở đâu?
Valentin

2
Điều này là do admin-sdk không có bất kỳ bổ sung Cloud Storage nào. Bạn có thể tải tài khoản dịch vụ admin-sdk của mình json tại đây console.firebase.google.com/project/_/settings/serviceaccounts/…
James Daniels

18
URL được tạo bằng phương pháp này rất dài. URL được tạo bởi phương pháp đề xuất @martemorfosis tốt hơn nhiều. Có bất kỳ chức năng nào tạo ra URL đó không? Đó là những gì tôi lưu trong cơ sở dữ liệu để sử dụng trong tương lai khi tôi sử dụng firebase-sdk. Phương thức nhân bản cần tồn tại trong miền Hàm.
Bogac

3
Làm cách nào chúng tôi có thể tải lên service-account.json cùng với các chức năng đã triển khai? Tôi đã thử đặt nó vào thư mục chức năng và tham chiếu nó trong trường tệp trong package.json nhưng nó không được triển khai. Cảm ơn bạn.
David Aroesti

2
Chúng tôi có được yêu cầu thêm actionexpires?
Chad Bingham

82

Dưới đây là một ví dụ về cách chỉ định mã thông báo tải xuống khi tải lên:

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

sau đó gọi với

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

Điều quan trọng ở đây là có một metadatađối tượng được lồng trong thuộc tính metadatatùy chọn. Đặt firebaseStorageDownloadTokensthành giá trị uuid-v4 sẽ yêu cầu Cloud Storage sử dụng giá trị đó làm mã thông báo xác thực công khai.

Rất cám ơn @martemorfosis


Làm cách nào để nhận được mã thông báo UUID hợp lệ cho tệp đã được tải lên trên Bộ nhớ? Tạo UUID ngẫu nhiên không giúp được gì. Bất kỳ gợi ý?
DerFaizio

3
Tìm thấy câu trả lời trong bài đăng @martemorfosis. UUID có thể được truy xuất từ ​​object.metadata export.uploadProfilePic = functions.storage.object (). OnChange (event => {const object = event.data; // Đối tượng lưu trữ. Const uuid = object.metadata.firebaseStorageDownloadTokens; // ...
DerFaizio

Cảm ơn bạn về ví dụ xô! Tôi đã cố gắng kết hợp khác nhau cho phương pháp xô và tập tin trong gần 1 giờ :)
JCarlosR

1
Cảm ơn câu trả lời của bạn! Trong trường hợp của tôi, tôi đang tải lên bằng bucket.file (fileName) .createWriteStream không trả về dữ liệu khi tải lên xong, do đó, tôi đã sử dụng encodeURIComponent (fileName) thay vì encodeURIComponent (file.name).
Stanislau Buzunko

2
Đây phải là câu trả lời đúng. Nó dẫn đến một URL tương tự như URL được tạo bởi SDK Firebase (@DevMike) và tôi cá rằng đó chính xác là những gì họ làm đằng sau hậu trường.
Samuel E.

64

Câu trả lời này sẽ tóm tắt các tùy chọn để lấy URL tải xuống khi tải tệp lên Google / Firebase Cloud Storage. Có ba loại URL tải xuống:

  1. URL tải xuống đã ký, là URL tạm thời và có các tính năng bảo mật
  2. URL tải xuống mã thông báo, liên tục và có các tính năng bảo mật
  3. URL tải xuống công khai, liên tục và thiếu bảo mật

Có ba cách để lấy URL tải xuống mã thông báo. Hai URL tải xuống khác chỉ có một cách để lấy chúng.

Từ Bảng điều khiển lưu trữ Firebase

Bạn có thể lấy URL tải xuống từ bảng điều khiển Firebase Storage:

nhập mô tả hình ảnh ở đây

URL tải xuống có dạng như sau:

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

Phần đầu tiên là một đường dẫn tiêu chuẩn đến tệp của bạn. Cuối cùng là mã thông báo. URL tải xuống này là vĩnh viễn, tức là, nó sẽ không hết hạn, mặc dù bạn có thể thu hồi nó.

getDownloadURL () Từ Giao diện Người dùng

Các tài liệu hướng dẫn cho chúng ta biết để sử dụng getDownloadURL():

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

Điều này nhận được cùng một URL tải xuống mà bạn có thể lấy từ bảng điều khiển lưu trữ Firebase của mình. Phương pháp này dễ dàng nhưng yêu cầu bạn phải biết đường dẫn đến tệp của mình, trong ứng dụng của tôi có khoảng 300 dòng mã, cho một cấu trúc cơ sở dữ liệu tương đối đơn giản. Nếu cơ sở dữ liệu của bạn phức tạp thì đây sẽ là một cơn ác mộng. Và bạn có thể tải tệp lên từ giao diện người dùng, nhưng điều này sẽ làm lộ thông tin đăng nhập của bạn cho bất kỳ ai tải xuống ứng dụng của bạn. Vì vậy, đối với hầu hết các dự án, bạn sẽ muốn tải tệp của mình lên từ Node back end hoặc Google Cloud Functions, sau đó lấy URL tải xuống và lưu nó vào cơ sở dữ liệu cùng với dữ liệu khác về tệp của bạn.

getSignedUrl () cho URL Tải xuống Tạm thời

getSignedUrl () dễ sử dụng từ Node back end hoặc Google Cloud Functions:

  function oedPromise() {
    return new Promise(function(resolve, reject) {
      http.get(oedAudioURL, function(response) {
        response.pipe(file.createWriteStream(options))
        .on('error', function(error) {
          console.error(error);
          reject(error);
        })
        .on('finish', function() {
          file.getSignedUrl(config, function(err, url) {
            if (err) {
              console.error(err);
              return;
            } else {
              resolve(url);
            }
          });
        });
      });
    });
  }

URL tải xuống đã ký trông giống như sau:

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 đã ký có ngày hết hạn và chữ ký dài. Tài liệu cho dòng lệnh gsutil signurl -d nói rằng các URL đã ký là tạm thời: thời hạn mặc định là một giờ và thời hạn tối đa là bảy ngày.

Ở đây tôi sẽ không nói rằng getSignedUrl không bao giờ nói rằng URL đã ký của bạn sẽ hết hạn sau một tuần. Mã tài liệu có3-17-2025 ngày hết hạn, gợi ý rằng bạn có thể đặt năm hết hạn trong tương lai. Ứng dụng của tôi hoạt động hoàn hảo và sau đó bị lỗi một tuần sau đó. Thông báo lỗi cho biết chữ ký không khớp, không phải URL tải xuống đã hết hạn. Tôi đã thực hiện các thay đổi khác nhau đối với mã của mình và mọi thứ đều hoạt động ... cho đến khi tất cả bị sập một tuần sau đó. Điều này đã diễn ra trong hơn một tháng thất vọng.

Công khai tệp của bạn

Bạn có thể đặt các quyền trên tệp của mình ở chế độ đọc công khai, như được giải thích trong tài liệu . Điều này có thể được thực hiện từ Trình duyệt lưu trữ đám mây hoặc từ máy chủ Node của bạn. Bạn có thể đặt một tệp ở chế độ công khai hoặc một thư mục hoặc toàn bộ cơ sở dữ liệu Lưu trữ của mình. Đây là mã Node:

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

Kết quả sẽ như thế này trong Trình duyệt lưu trữ đám mây của bạn:

nhập mô tả hình ảnh ở đây

Sau đó, bất kỳ ai cũng có thể sử dụng đường dẫn chuẩn để tải xuống tệp của bạn:

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

Một cách khác để công khai tệp là sử dụng phương thức makePublic () . Tôi đã không thể làm cho điều này hoạt động, thật khó để sử dụng đúng đường dẫn của nhóm và tệp.

Một cách thay thế thú vị là sử dụng Danh sách Kiểm soát Truy cập . Bạn chỉ có thể cung cấp tệp cho những người dùng mà bạn đưa vào danh sách hoặc sử dụngauthenticatedRead để cung cấp tệp cho bất kỳ ai đã đăng nhập từ tài khoản Google. Nếu có tùy chọn "bất kỳ ai đăng nhập vào ứng dụng của tôi bằng Firebase Auth", tôi sẽ sử dụng tùy chọn này, vì nó sẽ giới hạn quyền truy cập chỉ cho người dùng của tôi.

Tạo URL tải xuống của riêng bạn với firebaseStorageDownloadTokens

Một số câu trả lời mô tả thuộc tính đối tượng Google Storage không có giấy tờ firebaseStorageDownloadTokens. Với điều này, bạn có thể cho Storage biết mã thông báo bạn muốn sử dụng. Bạn có thể tạo mã thông báo bằng uuidmô-đun Node. Bốn dòng mã và bạn có thể tạo URL tải xuống của riêng mình, cùng một URL tải xuống mà bạn nhận được từ bảng điều khiển hoặc getDownloadURL(). Bốn dòng mã là:

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

Đây là mã trong ngữ cảnh:

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

Đó không phải là lỗi đánh máy - bạn phải lồng firebaseStorageDownloadTokenstrong hai lớp metadata:!

Doug Stevenson đã chỉ ra rằng đó firebaseStorageDownloadTokenskhông phải là một tính năng chính thức của Google Cloud Storage. Bạn sẽ không tìm thấy nó trong bất kỳ tài liệu nào của Google và không có gì hứa hẹn rằng nó sẽ có trong phiên bản tương lai của @google-cloud. Tôi thích firebaseStorageDownloadTokensvì đó là cách duy nhất để đạt được thứ tôi muốn, nhưng nó có “mùi” không an toàn khi sử dụng.

Tại sao Không có getDownloadURL () từ Node?

Như @Clinton đã viết, Google nên tạo file.getDownloadURL()một phương thức trong @google-cloud/storage(tức là Node back end của bạn). Tôi muốn tải lên một tệp từ Google Cloud Functions và lấy URL tải xuống mã thông báo.


10
Tôi đã tạo một vấn đề cho vấn đề @google-cloud/storagenày, vui lòng +1 vấn đề này;) github.com/googleapis/nodejs-storage/issues/697
Théo Champion,

1
liên kết makePublic () mới nhất .
galki

1
Có vẻ như firebaseStorageDownloadTokenskhông hoạt động nữa.
Mason

1
Câu trả lời được chấp nhận cho thấy rằng không thể nhận được một url tải xuống liên tục không hết hạn, điều này không đúng. Chi tiết ở đây trong câu trả lời của bạn là tuyệt vời và nên được đánh dấu là câu trả lời đúng. Cảm ơn bạn.
DevMike

2
@thomas cảm ơn vì bản tóm tắt tuyệt vời! Bạn đã đề cập có 3 cách để lấy URL tải xuống mã thông báo liên tục nhưng bạn chỉ chia sẻ 2: (a) Từ Bảng điều khiển lưu trữ Firebase và (b) getDownloadURL () Từ Giao diện người dùng. Không biết cách thứ 3 là gì?
czphilip

23

Với những thay đổi gần đây trong phản hồi của đối tượng hàm, bạn có thể nhận được mọi thứ bạn cần để "ghép" URL tải xuống lại với nhau như sau:

 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
Bạn đang đề cập đến phản hồi đối tượng từ bucket.file().upload()? Tôi không nhận được bất kỳ thuộc tính siêu dữ liệu nào trong dữ liệu phản hồi và tôi không chắc chắn về cách lấy các thuộc tính này firebaseStorageDownloadTokens.
Dygerati

cũng [BUCKET CỦA BẠN] là bucket.name, bạn không cần phải hardcode nó hoặc sử dụng một var địa phương thêm
Călin Darie

4
Vấn đề với giải pháp này là URL dịch vụ được mã hóa cứng. Nếu Firebase / Google thay đổi nó, nó có thể bị hỏng. Sử dụng metadata.mediaLinktài sản ngăn chặn một vấn đề như vậy.
Laurent

2
Trường hợp này không được hỗ trợ để tạo một URL như thế này. Nó có thể hoạt động ngày hôm nay, nhưng có thể bị hỏng trong tương lai. Bạn chỉ nên sử dụng các API được cung cấp để tạo URL tải xuống thích hợp.
Doug Stevenson

1
Dựa vào một URL được mã hóa cứng có thể thay đổi là một lựa chọn tồi.
Laurent

23

Nếu đang làm việc trên một dự án Firebase, bạn có thể tạo các URL đã ký trong Chức năng đám mây mà không bao gồm các thư viện khác hoặc tải xuống tệp thông tin xác thực. Bạn chỉ cần kích hoạt API IAM và thêm vai trò vào tài khoản dịch vụ hiện có của mình (xem bên dưới).

Khởi tạo thư viện quản trị và nhận tham chiếu tệp như bình thường của bạn:

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

Sau đó, bạn tạo một URL đã ký với

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

Đảm bảo rằng tài khoản dịch vụ Firebase của bạn có đủ quyền để chạy điều này

  1. Đi tới bảng điều khiển API của Google và bật API IAM ( https://console.developers.google.com/apis/api/iam.googleapis.com/overview )
  2. Vẫn trong bảng điều khiển API, hãy chuyển đến menu chính, "IAM & admin" -> "IAM"
  3. Nhấp vào chỉnh sửa cho vai trò "Tài khoản dịch vụ mặc định của App Engine"
  4. Nhấp vào "Thêm vai trò khác" và thêm vai trò có tên "Người tạo mã thông báo tài khoản dịch vụ"
  5. Lưu và đợi một phút để các thay đổi có hiệu lực

Với cấu hình Firebase vani, lần đầu tiên bạn chạy mã trên, bạn sẽ gặp lỗi API quản lý quyền truy cập và nhận dạng (IAM) chưa được sử dụng trong dự án XXXXXX trước đó hoặc nó bị vô hiệu hóa. . Nếu bạn nhấp vào liên kết trong thông báo lỗi và bật API IAM, bạn sẽ gặp một lỗi khác: Cần có quyền iam.serviceAccounts.signBlob để thực hiện thao tác này trên tài khoản dịch vụ my-service-account . Thêm vai trò của Người tạo mã thông báo sẽ khắc phục sự cố quyền thứ hai này.


Tôi chỉ định để lại câu trả lời với những chi tiết cơ bản giống như vậy mà tôi CUỐI CÙNG đã tìm ra một cách khó khăn - chắc chắn ước gì tôi đã đọc hết các giải pháp này trước đó: / Điều này đã hiệu quả với tôi kể từ ngày 12/12/18. Cảm ơn vì các hướng dẫn chi tiết, rất hữu ích cho người mới bắt đầu của chúng tôi !!
Kat

2
Signurl của tôi sẽ hết hạn sau 2 tuần nữa nhưng tôi đang sử dụng admin.initializeApp () mà không có khóa, đây có phải là vấn đề không? Tôi đã đặt tài khoản dịch vụ mặc định của ứng dụng App Engine thành "chủ sở hữu" và Đại lý dịch vụ chức năng đám mây, tôi vừa xóa "chủ sở hữu" ngay bây giờ và thêm "Người tạo mã thông báo tài khoản dịch vụ"
Amit Bravo

2
URL đã ký sẽ hết hạn sau 7 ngày. Bạn có thể đặt ngày hết hạn ngắn hơn nhưng không được dài hơn.
Thomas David Kehoe

Làm thế nào để làm mới url nếu nó hết hạn?
Manoj MM

làm thế nào để làm mới url để đặt nó thành thời gian dài hơn?
Saifallak

17

Một phương pháp mà tôi đang sử dụng thành công là đặt giá trị UUID v4 thành khóa có tên firebaseStorageDownloadTokenstrong siêu dữ liệu của tệp sau khi tải lên xong rồi tự lắp ráp URL tải xuống theo cấu trúc mà Firebase sử dụng để tạo các URL này, ví dụ:

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

Tôi không biết mức độ "an toàn" khi sử dụng phương pháp này (vì Firebase có thể thay đổi cách tạo URL tải xuống trong tương lai) nhưng nó rất dễ thực hiện.


1
Bạn có một ví dụ nơi bạn đặt giá trị uuid không?
Drew Beaupre

1
Tôi có cùng câu hỏi với Drew, bạn đặt siêu dữ liệu ở đâu? Tôi đã cố gắng đặt trong khi hàm bucket.upload, không hoạt động.
Vysakh Sreenivasan

1
Vysakh, tôi đã đăng một câu trả lời đầy đủ với ví dụ. Hy vọng rằng sẽ giúp bạn.
Drew Beaupre

Bạn tạo mã thông báo ở đâu / như thế nào?
CodyBugstein,

3
Tôi sẽ không coi kỹ thuật này là "an toàn", vì URL tải xuống có nghĩa là không rõ ràng, mà các thành phần của chúng không được chia nhỏ hoặc lắp ráp.
Doug Stevenson,

16

Đối với những người thắc mắc tệp Firebase Admin SDK serviceAccountKey.json sẽ đi đâu. Chỉ cần đặt nó vào thư mục chức năng và triển khai như bình thường.

Nó vẫn khiến tôi bối rối tại sao chúng tôi không thể lấy url tải xuống từ siêu dữ liệu như chúng tôi làm trong SDK Javascript. Việc tạo ra một url cuối cùng sẽ hết hạn và lưu nó vào cơ sở dữ liệu là không mong muốn.


15

Tôi khuyên bạn nên sử dụng tùy chọn predefinedAcl: 'publicRead'khi tải lên tệp bằng Cloud Storage NodeJS 1.6.x hoặc +:

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

bucket.upload(attachment, options);

Sau đó, việc lấy URL công khai đơn giản như sau:

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
Điều đó trên thực tế dường như hoạt động. Nhược điểm duy nhất mà tôi thấy cho đến nay là nếu bạn nhấn vào hình ảnh trong thanh URL của trình duyệt, nó sẽ tải xuống hình ảnh thay vì xem nội tuyến.
Michael Giovanni Pumo

file.getMetadata () đã thực hiện thủ thuật cho tôi sau khi sử dụng phương thức save () trên tham chiếu tệp. Sử dụng nó trong NodeJS với sdk firebase-admin.
Pascal Lamers

không hoạt động, tôi nhận được Người gọi ẩn danh không có quyền truy cập vào storage.objects.get vào your_app / image.jpg
Manoj MM

9

Xin lỗi nhưng tôi không thể gửi bình luận cho câu hỏi của bạn ở trên vì thiếu danh tiếng, vì vậy tôi sẽ đưa nó vào câu trả lời này.

Thực hiện như đã nêu ở trên bằng cách tạo Url đã ký, nhưng thay vì sử dụng service-account.json, tôi nghĩ bạn phải sử dụng serviceAccountKey.json mà bạn có thể tạo tại (thay thế YOURPROJECTID cho phù hợp)

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

Thí dụ:

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

Tôi không thể bình luận về câu trả lời mà James Daniels đưa ra, nhưng tôi nghĩ điều này rất quan trọng để đọc.

Đưa ra một URL có chữ ký Giống như anh ấy đã làm trong nhiều trường hợp khá tệ và có thể Nguy hiểm . Theo tài liệu của Firebase, url đã ký sẽ hết hạn sau một thời gian, vì vậy việc thêm url đó vào cơ sở dữ liệu của bạn sẽ dẫn đến url trống sau một khung thời gian nhất định

Có thể do hiểu nhầm Tài liệu ở đó và url đã ký không hết hạn, do đó sẽ có một số vấn đề bảo mật. Khóa dường như giống nhau cho mọi tệp được tải lên. Điều này có nghĩa là khi bạn có url của một tệp, ai đó có thể dễ dàng truy cập vào các tệp mà anh ta không được hỗ trợ để truy cập, chỉ bằng cách biết tên của họ.

Nếu tôi hiểu sai điều đó thì tôi sẽ rất mong được sửa chữa. Người khác có lẽ nên Cập nhật giải pháp có tên ở trên. Nếu tôi có thể sai ở đó


7

Đây là những gì tôi hiện đang sử dụng, nó đơn giản và hoạt động hoàn hảo.

Bạn không cần phải làm bất cứ điều gì với Google Cloud. Nó hoạt động hiệu quả với 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

CHỈNH SỬA: Cùng một ví dụ, nhưng với tải lên:

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

cập nhật:

không cần thực hiện hai lệnh gọi khác nhau trong phương thức tải lên để lấy siêu dữ liệu:

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

1
Bạn sẽ sử dụng nó như thế nào với một tệp không được mã hóa base64?
Tibor Udvari

1
Nó không phải mediaLinkenter, nó chỉ là mediaLink
l2aelba

1
Tôi không thể tìm thấy mediaLink i.stack.imgur.com/B4Fw5.png
sarah

@Sarah Tôi đã viết điều này bằng cách sử dụng bản ghi, không chắc liệu có một số thay thế mô-đun hay không.
Oliver Dixon

3

Tôi đã gặp vấn đề tương tự, tuy nhiên, tôi đang xem mã của ví dụ hàm firebase thay vì README. Và Câu trả lời trên chủ đề này cũng không giúp được gì ...

Bạn có thể tránh chuyển tệp cấu hình bằng cách làm như sau:

Đi tới Bảng điều khiển đám mây của dự án > IAM & quản trị> IAM , Tìm tài khoản dịch vụ mặc định của App Engine và thêm vai trò Người tạo mã thông báo tài khoản dịch vụ cho thành viên đó. Điều này sẽ cho phép ứng dụng của bạn tạo URL công khai đã ký cho hình ảnh.

source: Tự động tạo chức năng hình thu nhỏ README

Vai trò của bạn đối với công cụ ứng dụng sẽ giống như sau:

Bảng điều khiển đám mây


3

Nếu bạn sử dụng giá trị danh sách kiểm soát truy cập được xác định trước của 'publicRead', bạn có thể tải tệp lên và truy cập tệp bằng cấu trúc url rất đơn giản:

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

Sau đó, bạn có thể tạo url như sau:

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

2

Điều này hoạt động nếu bạn chỉ cần một tệp công khai với một URL đơn giản. Lưu ý rằng điều này có thể vượt quá quy tắc lưu trữ Firebase của bạn.

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

Đối với những người đang sử dụng SDK Firebase và admin.initializeApp:

1 - Tạo Khóa riêng và đặt trong thư mục / functions.

2 - Định cấu hình mã của bạn như sau:

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

Tài liệu

Việc thử / bắt là do tôi đang sử dụng index.js để nhập các tệp khác và tạo một hàm cho mỗi tệp. Nếu bạn đang sử dụng một tệp index.js duy nhất với tất cả các chức năng, bạn sẽ ổn admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));.


đối với tôi nó là '../serviceaccountkey.json' nhưng cảm ơn cho người đứng đầu lên để sử dụng ../
robert vua

1

Kể từ firebase 6.0.0, tôi đã có thể truy cập trực tiếp vào bộ nhớ với quản trị viên như sau:

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

Vì vậy, tôi không cần thêm tài khoản dịch vụ. Sau đó, đặt UUID như được tham chiếu ở trên đã hoạt động để lấy url firebase.


1

Đây là điều tốt nhất tôi nghĩ ra. Nó là thừa, nhưng giải pháp hợp lý duy nhất đã làm việc cho tôi.

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

Không signedURL()sử dụngmakePublic()

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

Nếu bạn gặp lỗi:

Chức năng đám mây của Google: request (…) không phải là một chức năng

thử cái này:

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

Tôi đã đăng ans của mình ... trong URL bên dưới Nơi bạn có thể nhận mã đầy đủ với giải pháp

Làm cách nào để tải trực tiếp hình ảnh được mã hóa base64 (chuỗi) lên nhóm Google Cloud Storage bằng 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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.