我的平台在上传到谷歌云存储时出现问题,我只在生产环境中遇到过,这真是令人头疼。我的平台使用 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/