Multer-s3 在手机上上传空文件

Jon*_*rin 5 javascript amazon-s3 node.js fabricjs multer-s3

我正在使用 angular 和 multer-s3 将文件从 angular 应用程序上传到节点服务器。在桌面上一切正常,但由于某种原因,当我尝试通过我的 iPhone 7 上传照片时,上传的文件已损坏。我在两台设备上使用相同的图像并运行相同的流程,但得到不同的结果,所以我假设它是因为移动设备?

这是我尝试在移动设备上打开 S3 文件时收到的警报

The file “1519398514215-test.png” could not be opened because it is empty.
Run Code Online (Sandbox Code Playgroud)

这是我的代码

var aws = require('aws-sdk');
var path = require('path');
var path3 = path.join(__dirname, "../config/config-aws.json");
var multer = require('multer');
var multerS3 = require('multer-s3');
var request = require('request');

aws.config.loadFromPath(path3);
var s3 = new aws.S3();
var fileName = '';
var uploadM = multer({
  storage: multerS3({
    s3: s3,
    bucket: 'XXXX',
    acl: 'public-read',
    metadata: function (req, file, cb) {
      cb(null, {fieldName: file.fieldname + '.png'});
    },
    key: function (req, file, cb) {
      fileName =  Date.now().toString() + "-" + file.originalname + '.png' ;
      cb(null, fileName)
    }
  })
});



router.post('/', uploadM.array('photos', 3), function(req,res) {
  if (res.error) {
    console.log(error.stack);
    return res.status(400).json({
      message: "Error",
      error: res.error
    });
  }
  const url = 'https://s3-us-west-2.amazonaws.com/XXXX/' + fileName;
  return res.status(200).json({
    fileName: url
  });
});
Run Code Online (Sandbox Code Playgroud)

这是我的客户端

sendImage() {
  const formData: FormData = new FormData();

  this.removeObjectFromCanvas('polygon');


  if (!fabric.Canvas.supports('toDataURL')) {
    alert('This browser doesn\'t provide means to serialize canvas to an image');
  } else {
    // window.open(this.canvas.toDataURL('png'));
    const image = new Image();
    image.src = this.canvas.toDataURL('png');



        const blob = this.dataURItoBlob(image.src);

        const file = new File([blob], 'test.png');


        formData.append('photos', file, 'test');



        this.postFile(formData);
      }


    }

    postFile(file) {
      this.fileService.post(file)
      .subscribe(data => {

      }, error => {
        console.log(error);
      });
    }
Run Code Online (Sandbox Code Playgroud)

更新 **********

所以发现你可以在移动设备上调试。看起来我发送的缓冲区中有数据。我的第一个想法是缓冲区没有发送。

在此处输入图片说明

**** 更新仍然无法弄清楚。我做了一些研究,它可能与 formData 和 append 有关吗?但正如您从上图所见,两者似乎都很好。会继续研究...

***** 更新肯定上传空文件。但它只在手机上?

在此处输入图片说明

此外,我在发送到节点服务器之前检查了 formData,似乎其中包含正确的数据。

*** 更新

好吧,更奇怪的经历。似乎multer-s3正在上传空文件,但是当我在服务器端获取文件并将其返回给客户端,然后读取该文件并显示它时,图像显示完美。所以 formData 不是问题,这是我假设的 multer-s3 的问题?

****更新我忘了提到我正在使用fabricjs并从画布中获取图像。我在某些地方读到那里可能有问题,但是就像我上面说的那样,当我将文件发送到服务器并将其发送回客户端时,读取文件后它完美地显示了图像。

****更新我尝试将 contentType 添加到 multer 方法,现在我在仅在移动设备上运行时收到 503 服务不可用错误。对于桌面来说,它很好。

aws.config.loadFromPath(path3);
var file1;
var s3 = new aws.S3();
var fileName = '';
var uploadM = multer({
  storage: multerS3({
    s3: s3,
    bucket: 'rent-z',
    acl: 'public-read',
    contentType: function (req, file, cb) {
      cb(null, 'image/png');
    },
    metadata: function (req, file, cb) {
      console.log(file);
      cb(null, {fieldName: file.fieldname});
    },
    key: function (req, file, cb) {
      fileName =  Date.now().toString() + "-" + file.originalname;
      file1 = file;
      cb(null, fileName)
    }
  })
}).array('photos', 1);



router.post('/', function(req,res) {
  uploadM(req, res, function (err) {
    if (err) {
      console.log(err);
      return res.status(400).json({
        message: "Error uploading to multer",
        error: err
      });
    }
  console.log('worked');

  if (res.error) {
    console.log(error.stack);
    return res.status(400).json({
      message: "Error",
      error: res.error
    });
  }
  // fs.readFile(req.body, function (err, data) { 
  const url = 'https://s3-us-west-2.amazonaws.com/rent-z/' + fileName;
  return res.status(200).json({
    fileName: url
  });
  // });
  })

});
Run Code Online (Sandbox Code Playgroud)

我什至尝试运行 multer-s3 的自动查找 mime-type 功能,但确实给出了相同的结果

**** 第 4 天

我开始调试这个问题已经 96 个小时了。没有取得任何进展。仍在试图弄清楚为什么它适用于桌面而不是移动设备。对于任何想要快速总结行为的人:

  1. 用户上传桌面图片

  2. 用户将图像放在画布上

  3. 使用比例图像

  4. 用户按下 sendImage

  5. 这将图像转换为 dataUri 然后 blob

  6. 这个 blob 被添加到一个附加到 formData 的文件中

  7. 这个formData被发送到一个nodejs服务器,在那里multer-s3中间件成功地将文件上传到s3

  8. 用户在手机上试穿

  9. 步骤 7 失败。文件已上传但为空。

如果有人对如何继续有任何想法,请告诉我。

Kay*_*der 5

我会将其作为“官方”答案,因为这可能适合您的需求。每当我遇到这样的复杂问题时,我的第一个想法通常是“我想知道是否有一个 API/SaaS/服务可以为我抽象这个问题。” 正如您所发现的,文件上传很棘手,尤其是当您开始投入我们现在必须处理的无数设备时。

我不会提及任何特定服务,但谷歌搜索“文件上传 saas”通常会为您找到顶级行业参与者。只需花费 25 - 50 美元/月,您就可以将文件上传抽象为一个非常简单的 API 调用。您现在不仅可以节省时间,而且(假设您选择了可靠的提供商)将来您不会再为文件上传而烦恼。SaaS 的职责是确保文件上传可以在 100 万台不同的设备上运行;SaaS 的工作是确保 S3 集成正常工作,即使 S3 的 api 发生变化;SaaS 的工作是确保用户在上传由于某种原因失败等情况下看到友好的消息。我可以花时间为我们的应用程序构建功能,而不是担心文件上传是否可以在 iPhone 47 上运行。

“但随后我就依赖于 SaaS,并根据他们的价格和功能集而生活”啊,但你可以最大限度地减少这个问题。对于我们使用的许多服务,我喜欢制作一个包装器/接口/无论你想怎么称呼它。在文件上传的情况下,我做了一个ES6模块:fileUploads.js

在这个模块中,我有一个方法upload。这个方法有什么作用?它只是简单地实现并抽象了【fileupload SaaS X】的API。如果将来我们想要或需要从 SaaS X 更改为 SaaS Y,我只需更改整个应用程序中的一件事:我的fileUpload.js模块。