使用Node.js将文件上传到Firebase Storage

52

我正在尝试理解如何使用Node.js在Firebase Storage中上传文件。我的第一次尝试是使用Firebase库:

"use strict";

var firebase = require('firebase');

var config = {
    apiKey: "AIz...kBY",
    authDomain: "em....firebaseapp.com",
    databaseURL: "https://em....firebaseio.com",
    storageBucket: "em....appspot.com",
    messagingSenderId: "95...6"
};

firebase.initializeApp(config);

// Error: firebase.storage is undefined, so not a function
var storageRef = firebase.storage().ref();

var uploadTask = storageRef.child('images/octofez.png').put(file);

// Register three observers:
// 1. 'state_changed' observer, called any time the state changes
// 2. Error observer, called on failure
// 3. Completion observer, called on successful completion
uploadTask.on('state_changed', function(snapshot){
    ...
}, function(error) {
    console.error("Something nasty happened", error);
}, function() {
  var downloadURL = uploadTask.snapshot.downloadURL;
  console.log("Done. Enjoy.", downloadURL);
});

但事实证明Firebase不能从服务器端上传文件,正如文档中明确指出的:

Firebase存储不包含在服务器端Firebase npm模块中。相反,您可以使用gcloud Node.js客户端。

$ npm install --save gcloud

在您的代码中,您可以通过以下方式访问您的存储桶:

var gcloud = require('gcloud')({ ... }); var gcs = gcloud.storage();
var bucket = gcs.bucket('<your-firebase-storage-bucket>');
我们能否在没有Google Cloud Platform帐户的情况下使用gcloud?如何操作?
如果不行,那么为什么可以从客户端上传文件到Firebase Storage?
我们不能简单地创建一个库来从服务器端发出相同的请求吗?
Firebase Storage与Google Cloud Platform有什么关联?为什么Firebase只允许我们从客户端上传图片?
我的第二次尝试是使用gcloud库,就像文档中提到的那样:
var gcloud = require("gcloud");

// The following environment variables are set by app.yaml when running on GAE,
// but will need to be manually set when running locally.
// The storage client is used to communicate with Google Cloud Storage
var storage = gcloud.storage({
  projectId: "em...",
  keyFilename: 'auth.json'
});

storage.createBucket('octocats', function(err, bucket) {

    // Error: 403, accountDisabled
    // The account for the specified project has been disabled.

    // Create a new blob in the bucket and upload the file data.
    var blob = bucket.file("octofez.png");
    var blobStream = blob.createWriteStream();

    blobStream.on('error', function (err) {
        console.error(err);
    });

    blobStream.on('finish', function () {
        var publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
        console.log(publicUrl);
    });

    fs.createReadStream("octofez.png").pipe(blobStream);
});
7个回答

21

在服务器上使用 Firebase 库时,通常会使用服务账号进行授权,因为这将使您对实时数据库等拥有管理员访问权限。您可以使用相同的服务帐户凭据文件来授权gcloud

顺便说一句:Firebase 项目实质上也是 Google Cloud Platform 项目,您可以在 https://console.firebase.google.comhttps://console.cloud.google.comhttps://console.developers.google.com 上访问您的 Firebase 项目。您可以在Firebase 控制台> 项目设置Cloud 控制台仪表板中查看您的项目 ID。

使用 gcloud SDK 时,请确保使用与 Firebase Storage 使用相同的(已存在的)存储桶。您可以在 Firebase web 的 config 对象或 Firebase Storage 标签中找到存储桶名称。基本上,您的代码应该从这里开始:

var gcloud = require('gcloud');

var storage = gcloud.storage({
  projectId: '<projectID>',
  keyFilename: 'service-account-credentials.json'
});

var bucket = storage.bucket('<projectID>.appspot.com');

...

我明白了,也许最好等待你的反馈。我给你写了一封电子邮件。谢谢! - Ionică Bizău
请问您能否看一下这个相关问题 - Ionică Bizău
那么我如何将一个Node.js应用程序上传到Firebase呢?因为我刚刚登录了我的Firebase帐户,这是我有一段时间没有使用过的,发现有链接到2个最近创建的Google Actions项目(这正是我想从Heroku移动到Firebase的内容),已经自动添加。但该链接将我带到控制台。我可以从我的Github连接部署它或从终端上传它吗?是否有任何视频链接教程可以提供参考? - marciokoko
service-account-credentials.json在哪里? - Aero Wang
1
"gloud"现在已经过时。 - ishandutta2007
显示剩余11条评论

19

当我尝试这样做时,我会得到TypeError: defaultStorage is not a function的错误。使用最新的firebase-admin npm库。 - Pat Needham
var bucket = firebaseAdmin.storage().bucket('bucketName'); - 这就是诀窍,按照这个指南进行操作:https://firebase.google.com/docs/storage/admin/start#use_a_custom_firebase_app - Pat Needham
如何在 bucket() 后获取一个 ref()?以下两种方法可行:bucket.ref() 或 bucket.child('path')。 - Baz

14

Firebase Admin SDK 允许您直接访问 Google Cloud 存储。

欲了解更多详情,请访问Introduction to the Admin Cloud Storage API

var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    storageBucket: "<BUCKET_NAME>.appspot.com"
});

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

bucket.upload('Local file to upload, e.g. ./local/path/to/file.txt')

如何在存储上下载文件? - Learn2Code
1
通过使用 getDownloadURL() 方法 - Madhav Kumar
谢谢你的回答!但是你能否分享一下如何使用getDownloadURL()的示例?再次感谢。 - Mohammed Alawneh
const destFilename = '本地文件目标路径,例如./local/path/to/file.txt';const options = { // 文件下载的路径,例如"./file.txt" destination: destFilename, }; bucket.file('需要下载的远程文件,例如file.txt').download(options)参考文献下载对象 - Madhav Kumar
@Learn2Code 上述代码将从存储中下载文件到本地。 - Madhav Kumar

8

我希望这对您有用。我从本地上传了一个文件,然后使用UUID添加了访问令牌,接着我将其上传到Firebase存储中。之后我生成了下载链接。如果我们点击该链接,它将自动下载文件。

    const keyFilename="./xxxxx.json"; //replace this with api key file
    const projectId = "xxxx" //replace with your project id
    const bucketName = "xx.xx.appspot.com"; //Add your bucket name
    var mime=require('mime-types');
    const { Storage } = require('@google-cloud/storage');
    const uuidv1 = require('uuid/v1');//this for unique id generation

   const gcs = new Storage({
    projectId: projectId,
    keyFilename: './xxxx.json'
     });
    const bucket = gcs.bucket(bucketName);

    const filePath = "./sample.odp";
    const remotePath = "/test/sample.odp";
    const fileMime = mime.lookup(filePath);

//we need to pass those parameters for this function
    var upload = (filePath, remoteFile, fileMime) => {

      let uuid = uuidv1();

      return bucket.upload(filePath, {
            destination: remoteFile,
            uploadType: "media",
            metadata: {
              contentType: fileMime,
              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);
          });
    }
//This function is for generation download url    
 upload(filePath, remotePath, fileMime).then( downloadURL => {
        console.log(downloadURL);

      });

4
请注意,gcloud已被弃用,请使用google-cloud代替。您可以在项目设置->服务帐户中找到SERVICE_ACCOUNT_KEY_FILE_PATH。
var storage = require('@google-cloud/storage');

var gcs = storage({
    projectId: PROJECT_ID,
    keyFilename: SERVICE_ACCOUNT_KEY_FILE_PATH
  });

// Reference an existing bucket.
var bucket = gcs.bucket(PROJECT_ID + '.appspot.com');

...

我按照您的描述进行设置后,如何下载图像? - Learn2Code
类型错误:storage 不是一个函数。你使用的 @google-cloud/storage 版本是什么?我的版本是 4.5.0。 - chirag

2
或者你可以像这样简单地填充XmlHttpRequest -
const XMLHttpRequest = require("xhr2");
global.XMLHttpRequest = XMLHttpRequest

并且导入

require('firebase/storage');

就这样,所有firebase.storage()方法现在都应该可以使用了。


类型错误:firebase.storage 不是一个函数。 - refik

0

我已经实现了API以在Firebase存储上上传文件:

const fs = require('firebase-admin');
const app = require('express')();
const serviceAccount = require('./serviceAccountKey_DEV.json');

fs.initializeApp({
    credential: fs.credential.cert(serviceAccount),
    storageBucket: `${serviceAccount.project_id}.appspot.com`
});

// Upload the file on firebase storage
app.get("/upload-on-firebase", async (req, res, next) => {
    var bucket = fs.storage().bucket();
    const result = await bucket.upload('data.json');
    console.log('result :', result);
    return res.send(result);
});

调用API上传:

curl --location --request GET 'http://localhost:3000/upload-on-firebase'

响应:

[
    {
        "_events": {},
        "_eventsCount": 0,
        "metadata": {
            "kind": "storage#object",
            "id": "project_id.appspot.com/data.json/1678222222",
            "selfLink": "https://www.googleapis.com/storage/v1/b/project_id.appspot.com/o/data.json",
            "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/project_id.appspot.com/o/data.json",
            "name": "data.json",
            "bucket": "project_id.appspot.com",
            "generation": "16787922222222",
            "metageneration": "1",
            "contentType": "application/json",
            "storageClass": "STANDARD",
            ....
            ....
            ....
        },
        "baseUrl": "/o",
    }
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接