Meteor CollectionFS:确保图像在显示之前已上传
Meteor CollectionFS: Make sure the image is uploaded before displaying
我正在使用带有 S3 适配器的 CollectionFS 包,我已经查看了几个不同的解决方案,但无法使其正常工作。
问题:即使 file/image 已成功上传到 S3,但在安全显示图像之前会触发成功上传的回调。这有时会导致显示损坏的图像。
我发现了 fileObj.once("uploaded", function(){})
回调,但似乎 "uploaded" 基本上意味着将图像发送到服务器。届时不会发生 S3 上传。我发现的一个临时解决方法是只使用 setTimeout
3-4 秒,但这并不可靠。
这是我的上传代码:
FS.Utility.eachFile(event, function(file) {
Session.set('profilePhotoUploaded', false);
var newFile = new FS.File(file);
newFile.metadata = {owner: Meteor.userId()};
ProfileImages.insert(newFile, function (err, fileObj) {
if (err){
console.log("error! - " + err);
} else {
// handle success depending what you need to do
var userId = Meteor.userId();
// This does NOT run when image is stored in S3. I think it runs when the image reached the app server.
fileObj.once("uploaded", function () {
// timeout of 3 seconds to make sure image is ready to be displayed
// --- This is not a good solution and it image does is not always ready
setTimeout(function(){
var uploadedImage = {
"profile.image.url": "/cfs/files/profileImages/" + fileObj._id
};
Meteor.users.update(userId, {$set: uploadedImage});
Session.set('profilePhotoUploaded', true);
}, 3000);
console.log("Done uploading!");
});
}
});
});
是否有不同的回调来检查图像是否已实际存储在 S3 中?我试过 fileObj.once("stored", function(){})
但这不起作用。
问题是 stored
挂钩会在原始图像保存在服务器上时触发,因此如果您要创建多个副本(缩略图),此挂钩会在缩略图存储之前触发。您可以通过检查 storeName 参数来检查存储了哪个版本的缩略图。在您定义 ProfileImages
集合的服务器端文件中,添加以下代码,将 'profilePhotoLarge'
替换为分配给您的 FS.Store.S3
商店的名称:
ProfileImages.on('stored', Meteor.bindEnvironment(function(fileObj, storeName) {
if (storeName === 'profilePhotoLarge') {
Meteor.users.update({_id: fileObj.metadata.owner}, {
$set: {
'profile.image.url': 'https://your AWS region domain/your bucket name/your folder path/' + fileObj._id + '-' +fileObj.name()
}
});
}
}, function() { console.log('Failed to bind environment'); }));
对于个人资料照片,我创建了一个 S3 存储桶并设置了允许任何人读取文件的权限,因此我将 URL 存储到 S3 上的图像,这在您的情况下可能不正确.由于用户对象在客户端是被动的,因此此更新将导致个人资料照片自动更新。
我发现 fileObj.hasStored("profileImages")
准确指定了图像存储在 S3 上的时间。所以在开始上传过程后,我只是每 1 秒启动一个计时器来检查它是否被保存。这可能不是最好的解决方案,但这对我有用。
FS.Utility.eachFile(event, function(file) {
Session.set('profilePhotoUploaded', false);
var newFile = new FS.File(file);
newFile.metadata = {owner: Meteor.userId()}; // TODO: check in deny that id is of the same user
ProfileImages.insert(newFile, function (err, fileObj) {
if (err){
console.log("error! - " + err);
} else {
// handle success depending what you need to do
var userId = Meteor.userId();
// Timer every 1 second
var intervalHandle = Meteor.setInterval(function () {
console.log("Inside interval");
if (fileObj.hasStored("profileImages")) {
// File has been uploaded and stored. Can safely display it on the page.
var uploadedImage = {
"profile.image.url": "/cfs/files/profileImages/" + fileObj._id
};
Meteor.users.update(userId, {$set: uploadedImage});
Session.set('profilePhotoUploaded', true);
// file has stored, close out interval
Meteor.clearInterval(intervalHandle);
}
}, 1000);
}
});
});
我正在使用带有 S3 适配器的 CollectionFS 包,我已经查看了几个不同的解决方案,但无法使其正常工作。
问题:即使 file/image 已成功上传到 S3,但在安全显示图像之前会触发成功上传的回调。这有时会导致显示损坏的图像。
我发现了 fileObj.once("uploaded", function(){})
回调,但似乎 "uploaded" 基本上意味着将图像发送到服务器。届时不会发生 S3 上传。我发现的一个临时解决方法是只使用 setTimeout
3-4 秒,但这并不可靠。
这是我的上传代码:
FS.Utility.eachFile(event, function(file) {
Session.set('profilePhotoUploaded', false);
var newFile = new FS.File(file);
newFile.metadata = {owner: Meteor.userId()};
ProfileImages.insert(newFile, function (err, fileObj) {
if (err){
console.log("error! - " + err);
} else {
// handle success depending what you need to do
var userId = Meteor.userId();
// This does NOT run when image is stored in S3. I think it runs when the image reached the app server.
fileObj.once("uploaded", function () {
// timeout of 3 seconds to make sure image is ready to be displayed
// --- This is not a good solution and it image does is not always ready
setTimeout(function(){
var uploadedImage = {
"profile.image.url": "/cfs/files/profileImages/" + fileObj._id
};
Meteor.users.update(userId, {$set: uploadedImage});
Session.set('profilePhotoUploaded', true);
}, 3000);
console.log("Done uploading!");
});
}
});
});
是否有不同的回调来检查图像是否已实际存储在 S3 中?我试过 fileObj.once("stored", function(){})
但这不起作用。
问题是 stored
挂钩会在原始图像保存在服务器上时触发,因此如果您要创建多个副本(缩略图),此挂钩会在缩略图存储之前触发。您可以通过检查 storeName 参数来检查存储了哪个版本的缩略图。在您定义 ProfileImages
集合的服务器端文件中,添加以下代码,将 'profilePhotoLarge'
替换为分配给您的 FS.Store.S3
商店的名称:
ProfileImages.on('stored', Meteor.bindEnvironment(function(fileObj, storeName) {
if (storeName === 'profilePhotoLarge') {
Meteor.users.update({_id: fileObj.metadata.owner}, {
$set: {
'profile.image.url': 'https://your AWS region domain/your bucket name/your folder path/' + fileObj._id + '-' +fileObj.name()
}
});
}
}, function() { console.log('Failed to bind environment'); }));
对于个人资料照片,我创建了一个 S3 存储桶并设置了允许任何人读取文件的权限,因此我将 URL 存储到 S3 上的图像,这在您的情况下可能不正确.由于用户对象在客户端是被动的,因此此更新将导致个人资料照片自动更新。
我发现 fileObj.hasStored("profileImages")
准确指定了图像存储在 S3 上的时间。所以在开始上传过程后,我只是每 1 秒启动一个计时器来检查它是否被保存。这可能不是最好的解决方案,但这对我有用。
FS.Utility.eachFile(event, function(file) {
Session.set('profilePhotoUploaded', false);
var newFile = new FS.File(file);
newFile.metadata = {owner: Meteor.userId()}; // TODO: check in deny that id is of the same user
ProfileImages.insert(newFile, function (err, fileObj) {
if (err){
console.log("error! - " + err);
} else {
// handle success depending what you need to do
var userId = Meteor.userId();
// Timer every 1 second
var intervalHandle = Meteor.setInterval(function () {
console.log("Inside interval");
if (fileObj.hasStored("profileImages")) {
// File has been uploaded and stored. Can safely display it on the page.
var uploadedImage = {
"profile.image.url": "/cfs/files/profileImages/" + fileObj._id
};
Meteor.users.update(userId, {$set: uploadedImage});
Session.set('profilePhotoUploaded', true);
// file has stored, close out interval
Meteor.clearInterval(intervalHandle);
}
}, 1000);
}
});
});