node.js - Google 存储桶文件上传在生产环境中不起作用

标签 node.js file-upload google-cloud-platform google-cloud-storage

我的平台在上传到谷歌云存储时出现问题,我只在生产环境中遇到过,这真是令人头疼。我的平台使用 NodeJS,此文件上传是在 API 服务的后端完成的。

语言:Javascript,nodejs 6.5 版

使用的包:@google-cloud/storage version 0.2.0, gm version 1.23.0

该服务实质上采用 base 64 格式的图像,创建图像缓冲区,然后将该图像通过管道传输到谷歌云存储桶。简单易行。

不幸的是,它在生产环境中不起作用,我不明白为什么。完全相同的代码在生产环境中运行,只是指向不同的存储桶。

文件顶部的一些相关代码

var gm = require('gm').subClass({ imageMagick: true });
var Promise = require('bluebird');
var Q = require('q');
var request = require('request').defaults({ encoding: null });
var gcs = require('@google-cloud/storage')({
      keyFilename: sails.config.gcloud.keyFileName,
      projectId: sails.config.gcloud.projectId
});
var bucket = gcs.bucket(sails.config.gcloud.buckets.cdn);

// Takes raw base64Image from client and converts it into:
// {
//      meta: data:image/jpeg;base64,
//      data: hugeStringOfImageDataInBase64,
//      dateType: image/jpeg
// }
function decodeImage(base64Image) {
    // Not using regex due to perf.
    var startImageData = base64Image.indexOf(',');
    var regex = /^data:(.+);base64$/;
    var meta = base64Image.slice(0, startImageData);
    var data = base64Image.slice(startImageData + 1);
    var dataType = meta.match(regex)[1];

    return { type: dataType, meta: meta, data: data };
}

创建buffer的相关代码

createNewPictureAndUploadToCDNBase: function(imageInBase64, imageBuffer, cb) {

    return Picture.create()
        .then(function(emptyPicture) {
            var buffer;

            if (imageInBase64) {
                buffer = PictureService.bufferFromBase64(imageInBase64);
            } else {
                buffer = imageBuffer;
            }

            return PictureService.resizeAndUploadPictureToCDN(emptyPicture.id, buffer, function (err, results) {

                emptyPicture = _.merge(emptyPicture, results);

                return emptyPicture.save(function(err) {
                    cb(err, emptyPicture);
                });
            });

        }).catch(function(err) {
            return cb(err);
        });
},

bufferFromBase64: function (imageInBase64) {
    return new Buffer(decodeImage(imageInBase64).data, 'base64');
},

文件通过管道传输到 Google Cloud Storage 存储桶的代码的主要部分

resizeAndUploadPictureToCDN: function (pictureId, imageBuffer, cb) {

    var resizingOptions = {
        original: {
            quality: 80,
            size: {}
        },
        thumbnail: {
            quality: 75,
            size: {
                width: 60,
                height: 60
            }
        },
        medium: {
            quality: 65,
            size: {height: 250}
        }
    };

    var resizingPromises = _.mapValues(resizingOptions, function (options, resizingName) {

        return new Promise(function (resolve, reject) {
            var file = bucket.file(pictureId + '-' + resizingName);

            // NOTE: 'gm' is a call to GraphicMagick for node
            // More can be found here: https://github.com/aheckmann/gm

            gm(imageBuffer)
                .quality(options.quality)
                .resize(options.size.width || null, options.size.height || null)
                .stream()
                .pipe(file.createWriteStream())
                .on('finish', function(err, success) {

                    file.getMetadata(function(err, metadata) {
                        if (err) {
                            console.log("Error getting metadata from google cloud", err);
                            return reject(err);
                        }

                        resolve(metadata.mediaLink);
                    });

                }).on('error', function(err) {
                    console.log("Got an error uploading to Cloud Storage:", err);
                    reject(err);
                });
        });
    });

    Promise.props(resizingPromises)
        .then(function (results) {
            cb(null, results);
        }).error(cb);
},

不要太担心调整大小的语言,我相信那部分不是问题。只需拍摄图像并上传几个不同尺寸的不同版本。与文件流和与 Google Cloud Storage 交互相比,我更有信心在本地与生产环境一样工作。

是的。当我在本地运行它并上传到一个存储桶时,效果很好。当它在生产中运行时,使用不同的存储桶,无法上传图像。

但是,在这两种情况下我都没有收到错误消息。相反,当它失败时,我仍然知道文件已成功上传。就在我访问该文件的位置时,在生产环境中它完全没有任何数据。

file.getMetaData()下从生产环境读取那个console.log

Corresponding metadata:  
{
    kind: 'storage#object',
    id: 'cdn.texasca.com/5a3d938b84d560010012b0b3-thumbnail/1513984907989412',
    selfLink: 'https://www.googleapis.com/storage/v1/b/cdn.texasca.com/o/5a3d938b84d560010012b0b3-thumbnail',
    name: '5a3d938b84d560010012b0b3-thumbnail',
    bucket: 'cdn.texasca.com',
    generation: '1513984907989412',
    metageneration: '1',
    timeCreated: '2017-12-22T23:21:47.915Z',
    updated: '2017-12-22T23:21:47.915Z',
    storageClass: 'STANDARD',
    timeStorageClassUpdated: '2017-12-22T23:21:47.915Z',
    size: '0',
    md5Hash: '1B2M2Y8AsgTpgAmY7PhCfg==',
    mediaLink: 'https://www.googleapis.com/download/storage/v1/b/cdn.texasca.com/o/5a3d938b84d560010012b0b3-thumbnail?generation=1513984907989412&alt=media',
    crc32c: 'AAAAAA==',
    etag: 'CKSji6XhntgCEAE=' 
}

请注意它是如何显示 size '0' 的,因为文件大小为 0。其他所有内容看起来完全与将文件流式传输到其他 google 后的效果相同来自本地环境的存储桶,除了它的文件大小类似于“13908”或类似大小,当您访问 mediaLink 位置时,它有一个全尺寸图像,而不是什么都没有。

我真的很难调试...

我应该从哪里开始调试这样的问题?是否有调试文件流的常用方法?有谁知道为什么我没有从这个文件流中收到错误消息?

真的想避免完全重写我平台的这一部分。

非常感谢任何帮助!

自最初发布问题以来我尝试过的事情

为了解决这个问题,到目前为止我已经尝试了一些方法。第一个是为服务帐户创建新 key 。所以我这样做了,将该键链接到我的代码中并进行了尝试。同样的问题,在本地开发模式下有效,在生产中不起作用(得到那个奇怪的非错误,它不会抛出错误但对象大小为 0)。

另外,正如我提到的,有两个桶。一个名为 dev0.cdn.texasca.com,另一个名为 cdn.texasca.com。在本地开发模式下,我将其切换为将图像上传到 cdn.texasca.com 而不是 dev one 和... BOOM!还是一样的问题。当我在本地运行平台但在生产中失败时效果很好。

我还尝试为我的服务帐户提供更多可能解决问题的“角色”。没有任何区别。

到目前为止,这就是我尝试过的所有内容。在这个问题上感觉真的很受阻,所以我要花一两天时间去做其他事情,这样我就可以得到一些有效的功能和错误修复。希望多提建议!

最佳答案

如果代码在一个存储桶上运行但在另一个存储桶上失败,则需要检查的是您运行代码所用的服务帐户,以及该服务帐户是否有权写入当前失败的目标生产存储桶.

这是一个链接,提供有关身份验证和存储范围的信息: https://cloud.google.com/storage/docs/authentication

此外,这里还有一个关于服务帐户的链接: https://cloud.google.com/iam/docs/understanding-service-accounts

如果这有帮助,请告诉我!

关于node.js - Google 存储桶文件上传在生产环境中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47949180/

相关文章:

javascript - 将缓冲文件数据转换为Json对象: express-fileupload

browser - HTTP大文件传输

google-app-engine - Google Cloud 中长时间运行的脚本

mongodb - 在集群外使用 StatefulSets 在 Kubernetes 上公开 MongoDB

javascript - 如何使用 Bower 构建依赖关系(例如highlight.js)?

php - Node.js 相当于 PHPlivedocx?

javascript - 上传本地文件,无需选择按钮

php - 每个字段上传多个文件并使用 codeigniter 存储在数据库中

php - 为什么找不到我的 php 页面?是我的yaml文件有问题吗?

node.js - 如何将 macchiato clojurescript 应用程序部署到 Heroku 免费帐户?