我使用angular和multer-s3将文件从角应用程序上传到节点服务器。一切都在桌面上运行良好但由于某些原因,当尝试通过我的iPhone 7上传照片时,上传的文件已损坏。我使用相同的图像并在两台设备上运行相同的流程,但得到不同的结果,因此我假设它是因为移动设备?
这是我尝试在移动设备上打开S3文件时收到的警报
The file “1519398514215-test.png” could not be opened because it is empty.
这是我的代码
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
});
});
这是我的客户端
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);
});
}
更新**********
所以发现你可以在手机上调试。看起来我发送的缓冲区中包含数据。我的第一个想法是缓冲区没有发送。
****更新 仍然无法弄清楚这一点。我做过一些研究,它可能与formData和附加有关吗?但正如您从上面的图像中看到的那样,两者似乎都很好。将继续研究......
*****更新 绝对上传空文件。但它只在移动设备上?
另外,我在发送到节点服务器之前检查了formData,似乎有正确的数据。
***更新
好的,即使是更奇怪的体验。似乎multer-s3正在上传空文件但是当我在服务器端获取文件并将其返回到客户端时,然后读取该文件并显示它,图像显示完美。所以formData不是问题,它是multer-s3的假设吗?
**** UPDATE 我忘了提到我正在使用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
});
// });
})
});
我甚至试过运行multer-s3的自动查找mime-type函数,确实给出了相同的结果
****第4天
自从我开始调试此问题以来已经过了96个小时。没有取得任何进展。仍在试图弄清楚为什么它在桌面而不是移动设备上工作。对于任何寻找行为快速摘要的人:
用户在桌面上传图片
用户将图片放在画布上
使用比例图像
用户按下sendImage
这会将图像转换为dataUri,然后转换为blob
此blob将添加到附加到formData
此formData被发送到nodejs服务器,其中multer-s3中间件 将文件成功上传到s3
用户试用手机
在步骤7失败。文件已上传但为空。
如果有人对如何继续有任何想法,请告诉我。
答案 0 :(得分:4)
我会让这个"官员"回答,因为这可能适合您的需求。任何时候我都有这样一个复杂的问题,我的第一个想法经常是#34;我想知道是否有可以为我抽象的API / SaaS /服务。"正如您所发现的那样,文件上传非常棘手,特别是当您开始投入我们现在必须处理的无数设备时。
我不会提及任何特定服务,但谷歌搜索"文件上传saas"通常会让你成为顶级的行业参与者。每月25美元 - 50美元,你可以将文件上传抽象为一个非常简单的api调用。您现在不仅可以节省时间,而且(假设您选择了一个可靠的提供商),您将来不会再担心文件上传。 SaaS的工作是确保文件上传能够在数百万种不同的设备上运行;确保S3集成工作是SaaS的工作,即使在S3的api发生变化时也是如此; SaaS的工作是确保用户在上传因某些原因失败时看到友好的好消息等等。我可以花时间为我们的应用构建功能,而不是担心是否担心文件上传工作在iPhone 47上。
"但后来我与SaaS联系在一起,并且随心所欲地生活在他们的价格和功能集中。啊,但你可以把这个问题减到最小。对于我们使用的许多服务,我喜欢创建一个包装器/接口/无论你想要什么。在文件上传的情况下,我制作了一个ES6模块:fileUploads.js
在这个模块中,我有一个方法upload
。这种方法有什么作用?它只是实现和抽象[fileupload SaaS X]的API。如果将来我们希望或需要从SaaS X更改为SaaS Y,我只需在整个应用程序中更改一件事:我的fileUpload.js
模块。