为什么在分段上传到aws lambda中快速运行时文件被破坏?

dan*_*wig 8 file-upload express multer aws-lambda axios

拥有带redux客户端和快递webapi的SPA.其中一个用例是将单个文件从浏览器上传到快速服务器.Express正在使用multer中间件解码文件上传并将其放入req对象的数组中.在localhost上运行时,一切都按预期工作.

但是,当应用程序部署到AWS时,它无法按预期运行.部署将express api推送到AWS Lambda函数,而redux客户端静态资产由Cloudfront CDN提供服务.在该环境中,上传的文件确实进入快速服务器,由multer处理,并且文件最终作为req.files数组中预期的第一个(也是唯一的)项.

问题是该文件包含错误的字节.例如,当我上传长度为2795字节的样本图像时,最终由multer解码的文件长度为4903字节.我尝试过的其他图像在multer解码并将它们放入req.files数组时,最终会变得大致相同.结果,文件已损坏,并且不显示为图像.

文件上传如下:

<input type="file" name="files" onChange={this.onUploadFileSelected} />
...
onUploadFileSelected = (e) => {
  const file = e.target.files[0]
  var formData = new FormData()
  formData.append("files", file)
  axios.post('to the url', formData, { withCredentials: true })
  .then(handleSuccessResponse).catch(handleFailResponse)
}
Run Code Online (Sandbox Code Playgroud)

我尝试过使用MemoryStorage和DiskStorage设置multer.两者都在localhost和aws lambda中工作,但两者都表现出相同的行为 - 文件大小更大并且在商店中已损坏.

我还尝试将multer设置为全局中间件(via app.use)和上传路由上的路由特定中间件(通过routes.post('the url', multerMiddlware, controller.uploadAction).再次,两者都表现出相同的行为.Multer中间件配置如下:

const multerMiddleware = multer({/* optionally set dest: '/tmp' */})
  .array('files')
Run Code Online (Sandbox Code Playgroud)

一个区别是在localhost上,客户端和快递都通过http提供,而在aws中,客户端和快递都通过https提供.我不相信这会有所不同,但我还是无法测试 - 要么通过https运行localhost,要么通过http运行aws.

我注意到的另一个奇怪的事情是,当multer中间件存在时,其他中间件似乎没有按预期运行.相反next(),其他中间件将在控制器动作调用之前完全退出,而当控制器调用退出时,控制不会在next()调用后流回middlware,而不是将功能移动到控制器操作.删除multer中间件后,其他中间件会按预期运行.但是,这种观察是在localhost上进行的,整个端到端用例确实按预期运行.

什么可能会在部署到云时弄乱上传的图像文件有效负载,但在localhost上却没有?难道真的是https有所作为吗?

更新1

当我上传此文件(11228字节)

这是HAR chrome给我的本地(预期)文件上传:

"postData": {
  "mimeType": "multipart/form-data; boundary=----WebKitFormBoundaryC4EJZBZQum3qcnTL",
  "text": "------WebKitFormBoundaryC4EJZBZQum3qcnTL\r\nContent-Disposition: form-data; name=\"files\"; filename=\"danludwig.png\"\r\nContent-Type: image/png\r\n\r\n\r\n------WebKitFormBoundaryC4EJZBZQum3qcnTL--\r\n"
}
Run Code Online (Sandbox Code Playgroud)

这是HAR chrome给我的aws(损坏)文件上传:

"postData": {
  "mimeType": "multipart/form-data; boundary=----WebKitFormBoundaryoTlutFBxvC57UR10",
  "text": "------WebKitFormBoundaryoTlutFBxvC57UR10\r\nContent-Disposition: form-data; name=\"files\"; filename=\"danludwig.png\"\r\nContent-Type: image/png\r\n\r\n\r\n------WebKitFormBoundaryoTlutFBxvC57UR10--\r\n"
}
Run Code Online (Sandbox Code Playgroud)

保存的损坏的图像文件长度为19369个字节.

更新2

我创建了一个文本文件,文本hello world长度为11个字节并上传.它不会在aws中被破坏.即使我使用txt或png后缀上传它也是如此,当持久化时它最终为11个字节.

更新3

尝试使用更大的文本文件(12132字节长)上传并且具有与更新2中相同的结果 - 文件保持原样,未损坏.

dan*_*wig 2

可能的答案:

找到这个https://forums.aws.amazon.com/thread.jspa?threadID=252327

API Gateway 本身不支持多部分表单数据。可以配置二进制直通,然后在集成(后端集成或 Lambda 函数)中处理此多部分数据。

如果您在 AWS 中使用 API 网关事件来触发托管 Express 服务器的 lambda,您似乎可能需要另一种方法。

或者,您可以将 API Gateway 配置为使用二进制有效负载/sf/answers/2923948191/

或者,直接从您的客户端上传到签名的 s3 url(或公共 URL),并使用它来触发另一个 lambda 事件。

在我们有机会尝试不同的API网关设置之前,我们找到了一个临时解决方法:使用FileReader将文件转换为base64文本字符串,然后提交。只要有效负载是文本,上传似乎就没有任何问题。