javascript - सफ़ारी 11.1: अजाक्स/XHR फॉर्म सबमिशन तब विफल हो जाता है जब इनपुट[टाइप=फाइल] खाली हो




jquery ajax (4)

मैं एक पर्ल-प्रोग्राम में एक ही मुद्दा प्रतीत होता है पर काम किया

Perl में मल्टीपार्ट / फॉर्म-डेटा को संसाधित करना एपल-डिवाइसेस के साथ अपाचे-त्रुटि को आमंत्रित करता है, जब एक फॉर्म-फाइल-तत्व खाली होता है

प्रपत्र को असाइन किए जाने से पहले प्रपत्र-तत्व को वर्कअराउंड हटा रहा है:

$('#myForm').find("input[type='file']").each(function(){
    if ($(this).get(0).files.length === 0) {$(this).remove();}
});
var fData = new FormData($('#myForm')[0]);
...

https://code.i-harness.com

अद्यतन : जैसा कि वेबकिट r230963 का निर्माण करता है , इस मुद्दे को वेबकिट में हल किया गया है।

===========

चूंकि मैकओएस और आईओएस पर हाल ही में सफारी 11.1 अपडेट, साथ ही सफारी टेक्नोलॉजी पूर्वावलोकन 11.2 में, मेरे वेब एप्लिकेशन में $.ajax कॉल तब विफल हो रही है जब input[type=file] फ़ील्ड में कोई फ़ाइल नहीं चुनी गई है (इसकी आवश्यकता नहीं है) मेरे रूप में)। जब फ़ील्ड में कोई फ़ाइल नहीं है तो कोई विफलता नहीं।

ajax की error कॉलबैक चलती है और सफ़ारी कंसोल में निम्न संदेश होता है: Failed to load resource: The operation couldn't be completed. Protocol error Failed to load resource: The operation couldn't be completed. Protocol error । मैं HTTPS हूं और एक ही डोमेन (और सर्वर) पर भी HTTPS के स्थान पर सबमिट कर रहा हूं।

11.1 अपडेट से पहले, $.ajax कॉल ठीक सबमिट की गई जब कोई फ़ाइल नहीं चुनी गई थी। क्रोम और फ़ायरफ़ॉक्स के नवीनतम संस्करणों में कोई समस्या नहीं है।

मेरे कोड के प्रासंगिक भाग:

इनपुट:

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

जेएस:

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 }
});

एक अस्थायी (उम्मीद के formData ) समाधान के रूप में, मैं एक खाली फ़ाइल फ़ील्ड का पता लगा रहा हूं और इसे formData कॉल से पहले formData से हटा रहा हूं और सब कुछ अपेक्षित / पहले काम करता है:

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

क्या मैं कुछ गलत कर रहा हूं, क्या सफारी के साथ कोई समस्या है, या क्या सफारी में कोई बदलाव हुआ है जिसे अब अजाक्स कॉल में ध्यान देने की आवश्यकता है?


यह मेरे लिए जांच का काम करता है कि इनपुट फ़ील्ड खाली है या नहीं। यदि रिक्त है, तो FormData बनाने से पहले इनपुट फ़ील्ड को अक्षम करें। FormData बनाने के बाद, "अक्षम" विशेषता को हटा दें। अन्य उत्तरों में अंतर यह है, कि मैं "इनपुट [0] .files.length == 0" के लिए खोज करता हूं।

// get the input field with type="file"
var input = $('#myForm').find("input[type='file']")

// add the "disabled" attribute to the input
if (input[0].files.length == 0) {
  input.prop('disabled', true);
}

// create the formdata  
var formData = new FormData($(this)[0]);

// remove the "disabled" attribute
input.prop('disabled', false);

वेबकिट का निर्माण r230963 के रूप में, इस मुद्दे को वेबकिट में हल किया गया है। मैंने डाउनलोड किया और उस बिल्ड को चलाया और पुष्टि की कि समस्या हल हो गई है। यह तय नहीं है कि सफारी के लिए एक सार्वजनिक रिलीज कब उपलब्ध होगी जिसमें यह फिक्स है।


अद्यतन: पुराना जवाब फ़ायरफ़ॉक्स में काम नहीं करता है।

फ़ायरफ़ॉक्स FormData.get() फ़ाइल (अन्य ब्राउज़रों में फ़ाइल ऑब्जेक्ट के बजाय FormData.get() पर FormData.get() लिए बस खाली स्ट्रिंग देता है। इसलिए पुराने वर्कअराउंड का उपयोग करते समय, खाली <input type="file"> को रिक्त <input type="text"> तरह भेजा जाएगा। दुर्भाग्य से, फॉर्मडाटा ऑब्जेक्ट बनाने के बाद खाली पाठ से एक खाली फ़ाइल को अलग करने का कोई तरीका नहीं है।

इस समाधान का उपयोग करें:

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)

लाइव डेमो: https://jsfiddle.net/ypresto/05Lc45eL/

गैर- 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')
})

रेल के लिए (रेल-उज् / जिक-उज्): https://gist.github.com/ypresto/cabce63b1f4ab57247e1f836668a00a5

पुराना उत्तर:

फ़िल्टरिंग फॉर्मडाटा (रविचंद्र अडिगा के जवाब में) बेहतर है क्योंकि यह किसी भी डोम में हेरफेर नहीं करता है।

लेकिन फॉर्मडेटा में भागों के क्रम की गारंटी उसी रूप में इनपुट तत्वों को दी जाती है , जो <form> विनिर्देशन के अनुसार है। अगर कोई इस कल्पना पर भरोसा करता है तो यह एक और बग पैदा कर सकता है।

नीचे स्निपेट फॉर्मडाटा ऑर्डर और खाली हिस्सा रखेगा।

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
}

लाइव उदाहरण यहाँ है: https://jsfiddle.net/ypresto/y6v333bq/

रेल के लिए, यहां देखें: https://github.com/rails/rails/issues/32440#issuecomment-381185380

(नोट: iOS 11.3 की सफारी में यह समस्या है लेकिन 11.2 नहीं है।)





safari