it-swarm.com.de

AJAX Die Anforderung schlägt fehl, wenn FormData () einschließlich leerer Dateieingaben in Safari 10.13.4 gesendet wird

Ich verwende eine auf Symfony 2.8 basierende Web-App, die Formulardaten mit Ajax an einen Controller zurücksendet.

Bisher hat alles gut funktioniert, aber seit dem letzten macOS-Update auf Version 10.13.4 beginnen Benutzer zu berichten, dass das Senden des Formulars in Safari nicht mehr funktioniert. Andere macOS-Versionen und andere Browser auf 10.13.4 funktionieren weiterhin einwandfrei. In Safari scheint dies ein Problem zu sein. Natürlich habe ich einen Fehlerbericht bei Apple eingereicht, aber ich glaube nicht, dass ich jemals Feedback von dort erhalten werde.

Ich konnte die Ursache des Problems isolieren: Das Senden von Daten, die eine leere Dateieingabe enthalten, schlägt fehl:

// safri_bug.html
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </head>
<body>
    <form name="app_booking" method="post" action="/test/submit.php">
        <div><input type="text" id="someValue" name="value"></div>
        <div><input id="thefile" type="file" name="file"></div>
    </form>

    <button id="bSubmit" type="button">Submit</button>

    <script>    
        $(document).ready(function() {              
            $('#bSubmit').click(function() {
                var form = $('form');
                var data = new FormData(form[0]);

                $.ajax({
                    url : '/submit.php',
                    type : 'POST',
                    data : data,
                    contentType: false,
                    processData: false,
                    context : this,
                    success : function(response) {
                            alert('success: ' + response);
                    },
                    error: function (xhr, ajaxOptions, thrownError) {
                            alert('error: ' + xhr.responseText + ' - ' + thrownError);
                    }
                });
            });
        });
    </script>
</body>
</html>


// submit.php
<?php 
    echo "OK";

Ergebnis

  • Das Senden des Formulars funktioniert auf allen getesteten Browsern und Plattformen einwandfrei, jedoch in Safari unter macOS 10.13.4
  • In Safari unter macOS 10.13.4:
    • Wenn keine Datei ausgewählt ist: Die Ajax-Anforderung wird etwa 20 Sekunden lang ausgeführt (Zeitüberschreitung beim Einbau?) Und kehrt mit einer leeren Antwort zurück. Der submit.php wirdNICHTaufgerufen. 
    • Wenn eine Datei ausgewählt wurde: Alles funktioniert gut ...

Also scheint dies ein Fehler im neuesten Safari-Update zu sein? Oder stimmt mein Code nicht?

Irgendeine Idee, wie man diesen Fehler verhindern kann?

13
Andrei Herford

Inzwischen fand ich diese schnelle und schmutzige Lösung. Aber eigentlich suche ich einen echten Workaround. Irgendwelche Ideen?

// Filter out empty file just before the Ajax request
// Use try/catch since Safari < 10.13.4 does not support FormData.entries()
try {
   for (var pair of data.entries()) {
      if (pair[1] instanceof File && pair[1].name == '' && pair[1].size == 0)
         data.delete(pair[0]);  
   }
} catch(e) {}
1
Andrei Herford

Andrei Herfords Lösung führt zum Absturz anderer Browser, die die entries () - Methode von FormData nicht unterstützen. Bei Verwendung von try/catch werden nur Ausführungsfehler und keine Syntaxfehler gefunden.

Unsere Lösung bestand in der Verwendung von reinem JavaScript, um das leere Dateieingabeelement before das FormData-Objekt zu erstellen.

for (i = 0; i < form.elements.length; i++) {
  if (form.elements[i].type == 'file') {
    if (form.elements[i].value == '') {
      form.elements[i].parentNode.removeChild(form.elements[i]);
    }
  }
}
6
lemonrock

Ich verwende FormData auf meiner Website und kann überprüfen, ob dies ein Problem mit der neuesten Version von Safari ist. Das Entfernen der leeren Datei behebt das Problem. Hier ist der Code, der für mich funktioniert hat:

  var form = $('#formID');
  var data = new FormData(form[0])

  //hack to fix safari bug where upload fails if file input is empty
  if (document.getElementById("fileID").files.length == 0 ) { //if the file is empty
      data.delete('fileID'); //remove it from the upload data
  }
6
Leopold Mc

Ich habe diese Lösung verwendet und arbeitet für mich.

var $form = $('#website_settings_form');
var $inputs = $('input[type="file"]:not([disabled])', $form); //select input files
    $inputs.each(function(_, input) {
        if (input.files.length > 0) return 
        $(input).prop('disabled', true) //if the input doesn't have uploaded files will be disable
    })
    var formData = new FormData($form[0]);// create the form data
    $inputs.prop('disabled', false);//enable fields again.
3
Antonio Reyes

Ich habe den Andrei-Vorschlag verwendet, der für die Safari funktionierte, aber den IE brach.

Die einzige Lösung, die ich für beide Browser finden konnte, war eval ().

Da es sich hierbei offenbar um einen Fehler handelt, der nur Safari 11 betrifft, wurde auch die Browserversion überprüft.

if(dataObj instanceof FormData && navigator.userAgent.match(/version\/11((\.[0-9]*)*)? .*safari/i)) {
    try {
        eval('for (var pair of dataObj.entries()) {\
            if (pair[1] instanceof File && pair[1].name === \'\' && pair[1].size === 0) {\
                dataObj.delete(pair[0]);\
            }\
        }');
    } catch(e) {}
}
0
Andrew Primeau