Safari experiences occasional failures with pre-signed post uploads to S3 when using multipart/form-data for file uploads

Lately, I've encountered issues with pre-signed post uploads to S3 that seem to be unique to Mobile Safari browsers. Interestingly, the error has also shown up occasionally on Desktop Safari.

Whenever this error occurs, it triggers a response from S3 indicating an "EntityTooSmall" code along with details about the proposed upload size being smaller than the minimum allowed size.

It's worth noting that the code used for presigning the S3 URL and uploading files functions smoothly on other browsers such as Chrome, Firefox, and Brave.

The problem seems to be related to how Safari handles appending file data to the FormData object, resulting in sporadic failures that are hard to pinpoint.

While Safari accurately reads the file size (used for creating the presigned URL), there appears to be an issue when attaching it to the form data object for upload.

The following code snippet is what works reliably on most browsers but experiences intermittent failures on 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  
          const presignUrl = resp.data.presignUrl  
          return this.uploadToS3(file, presignUrl, presignUrl, presignFields)
        })
    },
    uploadToS3 (file, presignUrl, presignFields) {
      formPostData = new FormData()

      for (const field in presignFields) {
        formPostData.append(field, presignFields[field])
      }

      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>

If anyone has any insights or suggestions on why these sporadic issues occur specifically on Safari, your feedback would be greatly appreciated.

Answer №1

If you find yourself waiting a long time for certain methods to complete, consider utilizing promises or implementing async / await functionality. This issue could potentially arise in any browser when processing large files, causing functions to return nothing instead of the expected output once executed.

An example using async / await on object methods:

// Reproducing 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");
  },
};

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

fixed();

To transform your methods into asynchronous operations that wait for completion, follow a pattern like this:

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

Answer №2

Hey there! To improve your code, consider implementing async/await to ensure that each function completes before moving on to the next one. You can try writing something like this:

async function performTasks() {
  await task1();
  await task2();
  await task3();
}

By using async/await, you can be certain that all your functions will execute properly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhancing Vue.js 2.0 Functionality: Leveraging Arguments with AJAX Requests using Axios

Looking for a way to pass arguments in methods when using ajax axios? Check out this Vue code snippet: var app = new Vue({ el: '#app', data: { urlAdmission: admissions: [ { name : 'asdf& ...

Having trouble with Javascript files failing to load while hosting a website on digital ocean?

Recently, I developed a web application using an express backend and the ejs view engine. Everything works perfectly fine when tested on my local machine. However, I encountered issues when trying to host it on a digitalocean droplet (Ubuntu 22.10 x64). Af ...

Unable to use addEventListener on media queries exceeding 768px

When testing the site on Firefox 49 and Chrome 63, I encountered the same issue. Clicking on each card worked fine on iPhone4, Galaxy 5, and iPhone 8 using Chrome. However, after switching orientations from 640px to 320px portrait view, the top card would ...

The error occurred while attempting to save the file to disk: 'setHeader() requires both a name and a value to be set.'

I am working on enabling image file uploads to the Node.js server in a MEAN Stack application. Utilizing ng-file-upload for the client-side angular directive has been successful so far. However, I have encountered an issue when attempting to pass the image ...

jQuery tip: prevent redundancy in your code by using fadeOut() efficiently

One common issue I encounter is: I have a potentially hidden element I need to perform certain actions on that element If the element is visible, then fade it out using fadeOut() Once the actions are completed, fade the element back in with fadeIn() The ...

Executing a webservice method in an html page using javascript without the need to refresh the page

Is it possible to call a webservice from an index.html page using JavaScript? My webservice is located at "localhost/ws/service.asmx" and the specific web method I want to call is called HelloWorld. The index.html page contains an HTML submit button whic ...

Ways to conceal the TippyJS tooltip so it doesn't show up on video embeds

My website has tooltips enabled, but I am looking to hide the tooltip pop-ups that appear specifically over youtube video embeds. Upon inspecting the webpage, I found the code snippet below that is associated with youtube videos: <div data-tippy-root id ...

Utilize PHP SVG images to trigger internal JavaScript code through the <img> tag

Here is a php function that generates an SVG image. public function actionJsTest() { header('Content-Type: image/svg+xml'); $svg = ''; $svg .= '<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/ ...

Customized length limits in Vue components

In the form, there is a field for the phone prefix and another one for the actual phone number. The validation needs to be dynamic, with the minimum length calculated using the formula 7 - phoneprefix.length and the maximum length as 15 - phoneprefix.lengt ...

Tips for looping through nested JSON data in Google Sheets

In my attempt to iterate through the nested "line_items" element in a JSON response triggered by a post event, I aim to populate a Google Sheets spreadsheet using Google Apps Script. My objective is to write the elements within each "line_item" into new ro ...

Updating radio button based on selection change in jQuery

I'm struggling with jQuery and can't seem to figure out how to change the selected radio button based on a value in another select box. <div class="radio-inline" id="sourceDiv" role="group"> <input type="radio" id="sourceBtns1" na ...

Utilizing Webpack for Effortless Image Loading in Angular HTML

I've been struggling with webpack and angular configuration. It seems like a simple issue, but I just can't seem to find the solution. Despite scouring Stack Overflow for answers, I'm still stuck. My HTML page looks like this (along with ot ...

Tips for incorporating confidence intervals into a line graph using (React) ApexCharts

How can I utilize React-ApexCharts to produce a mean line with a shaded region to visually represent the uncertainty of an estimate, such as quantiles or confidence intervals? I am looking to achieve a result similar to: ...

Error message: "An internal server issue occurred while attempting to upload an image in base64 format via AWS Lambda

I've been working on uploading images to S3 using AWS Lambda. I found some helpful code in a URL and made some modifications to the variables fileFullPath and Bucket: Upload Image into S3 bucket using Api Gateway, Lambda funnction const AWS = requir ...

Harness the Power of JSON in your JavaScript Applications

I have come across many examples on Stack Overflow discussing how to parse JSON into a JavaScript object or convert JSON to a JS object. However, I haven't found an example that demonstrates binding JSON to an already defined JS object. I am currently ...

What is the best way to combine two JavaScript objects?

One object I am currently working with resembles the following structure let ob1 = { 'item_data':{ 'stack':{ 'purchase':'12345', 'order':'22222' } } } Additionally, I have anothe ...

How can I utilize an external file in Node js to output as a response?

I came across a similar inquiry, but I am interested in exploring manual methods. My goal is to achieve this without relying on express or any other external library. var http = require('http'); var server = http.createServer(function(req, res) ...

Issue with Installing Vue CLI Plugin Vue-ChartJS

For my project, I am utilizing Vue CLI and planning to incorporate the vue-chartjs plugin. In order to set it up, I followed this instructional guide: . However, upon running the process, I encountered an error with the npm package: https://i.sstatic.net ...

Rotate the mat-select arrow when the dropdown opens (moving in both upward and downward directions)

Currently, I have a mat-select dropdown icon arrow that toggles facing up or down based on user clicks. However, after selecting an option and closing the dropdown, the arrow remains in the upward position unless further clicked and held. I have attempted ...

Searching through an array of objects in MongoDB can be accomplished by using the appropriate query

Consider the MongoDB collection 'users' with the following document: { _id: 1, name: { first: 'John', last: 'Backus' }, birth: new Date('Dec 03, 1924'), death: new Date('Mar 1 ...