【问题标题】:Meteor CollectionFS: Make sure the image is uploaded before displayingMeteor CollectionFS:确保图像在显示前已上传
【发布时间】:2015-06-01 12:53:06
【问题描述】:

我正在使用带有 S3 适配器的 CollectionFS 包,我查看了一些不同的解决方案,但无法使其正常工作。

问题:即使文件/图像已成功上传到 S3,但在安全显示图像之前触发了成功上传的回调。这有时会导致显示损坏的图像。

我发现了fileObj.once("uploaded", function(){}) 回调,但似乎“已上传”基本上意味着将图像发送到服务器。到那时 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(){}) 但这不起作用。

【问题讨论】:

    标签: javascript file-upload meteor amazon-s3


    【解决方案1】:

    问题是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 上,这在您的情况下可能不正确。由于用户对象在客户端是响应式的,因此此更新将导致个人资料照片自动更新。

    【讨论】:

    • 实际上,我认为这确实可行。但事实并非如此。而且我认为提到了原因github.com/CollectionFS/Meteor-CollectionFS/issues/351 - 服务器上的集合上的“存储”事件现在应该可以正常工作。您现在还可以在服务器上执行 fileObj.on("stored", func) 并在客户端执行 fileObj.on("uploaded", func)。最终,我们计划在客户端为集合和 fileObjs 发出“存储”,但这比较棘手,还没有实现。
    • 所以我试图在客户端上获得“存储”回调。我猜这将在服务器端起作用。我想我已经找到了一个解决方法,虽然使用计时器。
    【解决方案2】:

    我发现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);
         }
       });
    });
    

    【讨论】:

    • 很糟糕,客户端还没有回调来告诉应用程序文件已安全存储,但这段代码现在必须做。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-03-21
    • 2015-06-02
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    相关资源
    最近更新 更多