type form example data javascript jquery ajax forms safari

javascript - example - Safari 11.1: el envío de formularios ajax/XHR falla cuando la entrada[tipo=archivo] está vacía



send form data ajax jquery (5)

ACTUALIZACIÓN : A partir de la versión r230963 de Webkit , este problema se ha resuelto en Webkit.

===========

Desde la reciente actualización de Safari 11.1 en macOS e iOS, así como en Safari Technology Preview 11.2, las llamadas $.ajax en mi aplicación web están fallando cuando un campo de input[type=file] no tiene ningún archivo elegido (no es necesario) en mi forma). No falla cuando el campo tiene un archivo elegido.

La devolución de llamada de error de ajax ejecuta y la consola de Safari contiene el siguiente mensaje: Failed to load resource: The operation couldn''t be completed. Protocol error Failed to load resource: The operation couldn''t be completed. Protocol error Soy HTTPS y estoy enviando a una ubicación en el mismo dominio (y servidor) también a través de HTTPS.

Antes de la actualización 11.1, la llamada a $.ajax envió $.ajax cuando no se eligió ningún archivo. Las últimas versiones de Chrome y Firefox no tienen problemas.

Partes relevantes de mi código:

La entrada:

Browse... <input id="file-upload" type="file" name="image" accept=".jpg,.jpeg">

El JS:

var formData = new FormData($(this)[0]); $.ajax({ type: ''POST'', enctype: ''multipart/form-data'', url: ''../process.php'', data: formData, contentType: false, processData: false, cache: false, success: function(response) { ... }, error: function() { //my code reaches here } });

Como una solución temporal (esperemos), estoy detectando un campo de archivo vacío y eliminándolo de formData antes de la llamada ajax y todo funciona como se esperaba / antes:

$("input[type=file]").each(function() { if($(this).val() === "") { formData.delete($(this).attr("name")); } });

¿Estoy haciendo algo mal? ¿Hay algún problema con Safari o hay un cambio en Safari que deba tenerse en cuenta ahora en las llamadas ajax?


A partir de la versión r230963 de Webkit , este problema se ha resuelto en Webkit. Descargué y ejecuté esa compilación y confirmé que el problema se resolvió. No hay idea de cuándo estará disponible una publicación pública para Safari que contenga esta solución.


Para la solución, elimino el archivo de tipo de entrada por completo de DOM usando el método jQuery remove ().

$("input[type=file]").each(function() { if($(this).val() === "") { $(this).remove(); } });



ACTUALIZACIÓN: la respuesta anterior NO funciona en Firefox.

Firefox solo devuelve una cadena vacía para FormData.get() en un campo de archivo vacío (en lugar de un objeto File en otros navegadores). Por lo tanto, cuando se utiliza la solución anterior, se enviará <input type="file"> como vacío <input type="text"> . Desafortunadamente, no hay forma de distinguir un archivo vacío de un texto vacío después de crear el objeto FormData.

Use esta solución en su lugar:

var $form = $(''form'') var $inputs = $(''input[type="file"]:not([disabled])'', $form) $inputs.each(function(_, input) { if (input.files.length > 0) return $(input).prop(''disabled'', true) }) var formData = new FormData($form[0]) $inputs.prop(''disabled'', false)

Demostración en vivo: https://jsfiddle.net/ypresto/05Lc45eL/

Para el entorno que no es jQuery:

var form = document.querySelector(''form'') var inputs = form.querySelectorAll(''input[type="file"]:not([disabled])'') inputs.forEach(function(input) { if (input.files.length > 0) return input.setAttribute(''disabled'', '''') }) var formData = new FormData(form) inputs.forEach(function(input) { input.removeAttribute(''disabled'') })

Para Rails (rails-ujs / jQuery-ujs): https://gist.github.com/ypresto/cabce63b1f4ab57247e1f836668a00a5

Vieja respuesta:

Filtrar FormData (en la respuesta de Ravichandra Adiga) es mejor porque no manipula ningún DOM.

Pero se garantiza que el orden de las partes en FormData sea el mismo que el de los elementos en forma , de acuerdo con la especificación <form> . Podría causar otro error si alguien confía en esta especificación.

A continuación, el fragmento mantendrá el orden de FormData y la pieza vacía.

var formDataFilter = function(formData) { // Replace empty File with empty Blob. if (!(formData instanceof window.FormData)) return if (!formData.keys) return // unsupported browser var newFormData = new window.FormData() Array.from(formData.entries()).forEach(function(entry) { var value = entry[1] if (value instanceof window.File && value.name === '''' && value.size === 0) { newFormData.append(entry[0], new window.Blob(), '''') } else { newFormData.append(entry[0], value) } }) return newFormData }

El ejemplo en vivo está aquí: https://jsfiddle.net/ypresto/y6v333bq/

Para Rails, mira aquí: https://github.com/rails/rails/issues/32440#issuecomment-381185380

(NOTA: Safari de iOS 11.3 tiene este problema pero 11.2 no).


var fileNames = formData.getAll("filename[]"); formData.delete("filename[]"); jQuery.each(fileNames, function (key, fileNameObject) { if (fileNameObject.name) { formData.append("filename[]", fileNameObject); } });

Prueba esto !!