简体   繁体   English

通过 multipart/form-data 内容类型上传文件时,在 Safari 中,预签名后上传到 S3 间歇性失败

[英]Pre-signed Post Uploads to S3 fails intermittently in Safari when uploading file via multipart/form-data content type

I've been experiencing pre-signed post upload failures to S3 that I cannot reproduce.我一直在遇到无法重现的 S3 的预签名后上传失败。 The failure happens mostly via Mobile Safari browsers, but my error log has shown that the error occurs on Desktop Safari as well.故障主要通过移动 Safari 浏览器发生,但我的错误日志显示桌面 Safari 也发生错误。

When the error occurs, I get the following error back from S3:发生错误时,我从 S3 收到以下错误:

<Error>
    <Code>EntityTooSmall</Code>
    <Message>Your proposed upload is smaller than the minimum allowed size</Message> 
    <ProposedSize>0</ProposedSize>
    <MinSizeAllowed>26254270</MinSizeAllowed>
    <...></...>
</error>

The code I'm using to presign the S3 Url and subsequently upload the file works fine in other browsers, eg Chrome, Firefox, Brave.我用来预签名 S3 Url 并随后上传文件的代码在其他浏览器中运行良好,例如 Chrome、Firefox、Brave。

Once I have the pre-signed URL, I'm creating a new FormData object and using the pre-signed fields to construct an object which I then send to S3 from the browser via Axios. Once I have the pre-signed URL, I'm creating a new FormData object and using the pre-signed fields to construct an object which I then send to S3 from the browser via Axios.

My guess is the error has something to do with Safari incorrectly appending the file data to the FormData object, but since it happens randomly, I can't figure out why.我的猜测是该错误与 Safari 错误地将文件数据附加到 FormData object 有关,但由于它是随机发生的,我不知道为什么。

Safari correctly reads the size of the file, as this value is used to create the presigned url, but when it comes time to attach it to the form data object and upload, something must be going wrong. Safari 正确读取了文件的大小,因为该值用于创建预签名的 url,但是当需要将其附加到表单数据 object 时,一定会出错并上传。

The following code is what I use with success on other browsers, and what works most of the time on safari:以下代码是我在其他浏览器上成功使用的代码,并且在 safari 上大部分时间都有效:


<script>

import axios from 'axios'
import getPresignUrl from './presign'

// Vue Component

export default {
  name: 'FinickyOnSafariUploader'
  data: () => ({
    // ...
  }),
  methods: {
    presignAndUpload (file) {
      const fileData = {
        fileName: file.name,
        fileType: file.type,
        fileSize: file.size
      }

      getPresignUrl(fileData)
        .then((resp) => {
          const presignFields = resp.data.presignFields  // Object
          const presignUrl = resp.data.presignUrl  // String
          return this.uploadToS3(file, presignUrl, presignUrl, presignFields)
        })
    },
    uploadToS3 (file, presignUrl, presignFields) {
      formPostData = new FormData()

      // Add Presigned Post Fields for Auth
      for (const field in presignFields) {
        formPostData.append(field, presignFields[field])
      }

      // Add Content-Type & File Data
      formPostData.append('Content-Type', file.type)
      formPostData.append('file', file)

      const req = {
        url: presignUrl,
        method: 'POST',
        headers: { 'Content-Type': 'multipart/form-data' },
        data: formPostData
      }

      return axios.request(req)
    }
  }
}


</script>


Does anyone have any guidance/insight as to why this happens sporadically and only on Safari?有没有人对为什么这种情况偶尔发生并且仅在 Safari 上发生有任何指导/见解?

It looks like you need to wait for the methods that take a long time to finish, to finish doing what they need to do.看起来您需要等待需要很长时间才能完成的方法,才能完成他们需要做的事情。 You can do this with promises or using async / await.你可以使用 Promise 或使用 async / await 来做到这一点。 I suspect you would be able to reproduce this error on any browser if you upload a big enough file, that would make your functions return nothing instead of something when they are done.我怀疑如果您上传足够大的文件,您将能够在任何浏览器上重现此错误,这将使您的函数在完成后什么也不返回。

You can use async / await on object methods like:您可以在 object 方法上使用 async / await,例如:

//First lets reproduce suspected error
const axios = require("axios");
const objError = {
  somefunction() {
    return axios.get("https://source.unsplash.com/random");
  },
};
console.log(objError.somefunction());

//the fix
const objFix = {
  async somefunction() {
    return await axios.get("https://source.unsplash.com/random");
  },
};

fixed = async () => {
  console.log(await objFix.somefunction());
};

fixed();

To convert your methods to do their job asynchronously and then wait for them you need to do something like:要将您的方法转换为异步完成工作,然后等待它们,您需要执行以下操作:

export default {
//...
  methods: {
    async presignAndUpload(file) {
      await getPresignUrl(fileData).then((resp) => {
        //...
        return await this.uploadToS3(file, presignUrl, presignUrl, presignFields);
      });
    },
    async uploadToS3(file, presignUrl, presignFields) {
      //...
      return await axios.request(req);
    },
  },
};

Good evening) I think you should use async/await.晚上好)我认为你应该使用 async/await。 I suppose your functions execute without waiting for finish.我想您的功能无需等待完成即可执行。 Write like像这样写

async function doUpload() {
  await operation1();
  await operation2();
  await operation3();
}

it can guarantee what all your functions executed correctly它可以保证您的所有功能都正确执行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将各种表单数据直接发布到 S3 预签名 URL? - How to directly POST various form data to a S3 pre-signed URL? 使用预先签名的POST URL将文件上载到AWS S3时设置随机文件名 - Set random file name when upload file to AWS S3 with pre-signed POST url 使用angular + aws-sdk-js +预签名网址将文件上传到S3 - Uploading a file to S3 with angular + aws-sdk-js + pre-signed url 通过 Safari 中的 multipart/form-data 发布的文件上传服务工作人员未触发“获取”事件侦听器 - "fetch" event listener not triggering in service worker for file upload via multipart/form-data post in Safari 如何提取通过 multipart/form-data 发送的文件的 Content-Type - How to extract the Content-Type of a file sent via multipart/form-data S3 预签名 URL 的格式 - Format of S3 pre-signed URLs POST文件多部分/表单数据(JavaScript)时出错 - Error when POST file multipart/form-data (JavaScript) 将画布图像上载为多部分/表单数据类型的Blob - Uploading a canvas image to facebook as Blob of multipart/form-data type 节点-多部分/表单数据上传文件,但无数据 - Node - multipart/form-data uploading file but no data 如何调用$ .post并设置内容类型Multipart / form-data数据 - How call $.post and set content type Multipart/form-data data
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM