【问题标题】:Retrieving images from Google Cloud Storage in Node.js without public URL在没有公共 URL 的 Node.js 中从 Google Cloud Storage 检索图像
【发布时间】:2017-04-02 17:17:45
【问题描述】:

我正在尝试将图像返回给我的用户以在 DOM 上查看,而不创建图像的公共链接(在取回图像之前,此路由受我的服务器的身份验证保护)。这是我迄今为止尝试过的,但这可能是错误的方法。

我正在按照 Google Cloud Storage with Node.js 指南向我的项目添加图片上传。我现在可以上传,并且图像正在保存在 Google Cloud Storage 中。该指南展示了如何检索公共 URL:

https://cloud.google.com/nodejs/getting-started/using-cloud-storage

我正在尝试使用文件流而不是公共 URL,这样我的图像就不会被公开。我猜它看起来类似于这个存储库中的流: https://github.com/GoogleCloudPlatform/google-cloud-node

但我试图在 HTTP 响应中返回图像,而不是简单地将它们本地存储在我的文件系统中。

我的客户端 Javascript 得到的响应看起来像一个巨大的 blob。 ����JFIF���Photoshop 3.08BIM� 元数据让我觉得这实际上是正确的图像,但我不知道如何让它看起来像图像。

这是我的节点服务器文件。上传到谷歌云存储,/post,正在工作,我可以看到正在添加的图像。

/get 正在返回看起来像一个巨大的 blob 的东西,看起来就像是我想要的图像(就像一个我不知道如何转换的奇怪 blob)。

我的代码如下所示:

var express = require('express');
var router = express.Router();
const Multer = require('multer');
const multer = Multer({
  storage: Multer.memoryStorage(),
  limits: {
    fileSize: 5 * 1024 * 1024 // no larger than 5mb, you can change as needed.
  }
});

const Storage = require('@google-cloud/storage');

const storage = Storage({
  keyFilename: 'server/firebase-service-account.json',
  projectId: process.env.FIREBASE_PROJECT_ID
});

const bucket = storage.bucket(process.env.FIREBASE_STORAGE_BUCKET);

// Process the file upload and upload to Google Cloud Storage.
router.post('/', multer.single('file'), (req, res, next) => {
  console.log('req.body', req.body);
  console.log('req.file', req.file);
  if (!req.file) {
    res.status(400).send('No file uploaded.');
    return;
  }

  // Create a new blob in the bucket and upload the file data.
  const blob = bucket.file(req.file.originalname);
  const blobStream = blob.createWriteStream();

  blobStream.on('error', (err) => {
    next(err);
    return;
  });

  blobStream.on('finish', () => {
    res.status(200).send('The image has been successfully uploaded to google cloud storage');
  });

  blobStream.end(req.file.buffer);
});

router.get('/', function (req, res, next) {
  var stream = bucket.file('Toast.jpg').createReadStream();

  stream.pipe(res);

  stream.on('data', function (data) {
    res.write(data);
  });

  stream.on('error', function (err) {
    console.log('error reading stream', err);
  });

  stream.on('end', function () {
    res.set({
      "Content-Disposition": 'attachment; filename="Toast.jpg"',
      "Content-Type": 'image/jpg'
    });
    res.end();
  });
});

module.exports = router;

这很接近吗?有没有更好的方法来使用我的身份验证来保护我的图像?

【问题讨论】:

  • 您知道 Firebase SDK for Cloud Storage,它与 Firebase 身份验证集成在一起,为开发人员提供简单直观的身份验证。 - firebase.google.com/docs/storage/#key_capabilities
  • 是的。在我的具体情况下,我没有使用 firebase 数据库,所以它不太适合我。我认为这对于使用数据库的人来说绝对是最好的选择。

标签: node.js google-cloud-storage


【解决方案1】:

我想错了。我只需将我的<img src="" 路由到正确的位置。

HTML

<img src="/uploads/1234">

服务器节点

var express = require('express');
var router = express.Router();
const Multer = require('multer');
const multer = Multer({
  storage: Multer.memoryStorage(),
  limits: {
    fileSize: 5 * 1024 * 1024 // no larger than 5mb, you can change as needed.
  }
});

const Storage = require('@google-cloud/storage');

const storage = Storage({
  keyFilename: 'server/firebase-service-account.json',
  projectId: process.env.FIREBASE_PROJECT_ID
});

const bucket = storage.bucket(process.env.FIREBASE_STORAGE_BUCKET);

// Process the file upload and upload to Google Cloud Storage.
router.post('/', multer.single('file'), (req, res, next) => {
  console.log('req.body', req.body);
  console.log('req.file', req.file);
  if (!req.file) {
    res.status(400).send('No file uploaded.');
    return;
  }

  // Create a new blob in the bucket and upload the file data.
  const blob = bucket.file(req.file.originalname);
  const blobStream = blob.createWriteStream();

  blobStream.on('error', (err) => {
    next(err);
    return;
  });

  blobStream.on('finish', () => {
    res.status(200).send('The image has been successfully uploaded to google cloud storage');
  });

  blobStream.end(req.file.buffer);
});

router.get('/:imageId', function (req, res, next) {
  var stream = bucket.file('Toast.jpg').createReadStream();

  res.writeHead(200, {'Content-Type': 'image/jpg' });

  stream.on('data', function (data) {
    res.write(data);
  });

  stream.on('error', function (err) {
    console.log('error reading stream', err);
  });

  stream.on('end', function () {
    res.end();
  });
});

module.exports = router;

我仍然希望得到有关这是否是解决此问题的正确方法的反馈。 (显然,硬编码将需要去。)

【讨论】:

  • 感谢 Luke 发布您找到的解决方案!它对我帮助很大。经过这么长时间,您最后是否坚持使用此解决方案?到目前为止,我所做的唯一区别是我使用 Google 的“下载”功能而不是 createReadStream 及其所有用具
  • 很高兴它有帮助!我不再维护这个项目,所以我不知道这段代码是否仍然是我推荐的解决方案。如果您有带有“下载”功能的简化解决方案,您应该发布它!
  • 完成!最后我不得不说我已经放置了 nginx 来代理对 GCP 的请求。我不希望 Nodejs 下载图像然后再次将其发送给用户,如果您知道我的意思,那将是两倍的速度。
【解决方案2】:

现在可以使用“下载”功能完成获取图像部分,这是我在 Typescript 中的 sn-p:

  async downloadImage(filename: string): Promise<Buffer> {
    try {
       // this.storageHandler is the Storage variable created with new Storage();
      const file = this.storageHandler.bucket(this.bucketName).file(filename);
      const imageDownloaded = await file.download();
      return imageDownloaded[0];
    } catch (err) {
      console.log('Handle the error as you want');
    }
    throw Error('Error while downloading image');
  }
}

【讨论】:

    猜你喜欢
    • 2020-03-24
    • 2018-09-24
    • 1970-01-01
    • 2017-12-17
    • 2020-04-17
    • 2017-07-08
    • 1970-01-01
    • 2017-01-16
    • 2014-01-18
    相关资源
    最近更新 更多