更新:自Webkit build r230963起,此问题已在Webkit中得到解决。
===========
自从最近在macOS和iOS上以及Safari Technology Preview 11.2中进行Safari 11.1更新以来,当$.ajax
字段没有选择文件时,我的Web应用程序中的input[type=file]
调用失败了我的表格中没有要求)。当 字段选择了文件时没有失败。
error
的{{1}}回调运行,Safari控制台包含以下消息:ajax
。我是HTTPS并通过HTTPS提交到同一域(和服务器)上的某个位置。
在11.1更新之前,Failed to load resource: The operation couldn’t be completed. Protocol error
调用在没有选择文件时提交正常。最新版本的Chrome和Firefox都没有问题。
我的代码的相关部分:
输入:
$.ajax
JS:
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
中删除,并且所有内容都按预期/之前工作:
ajax
我做错了什么,Safari是否有问题,或者现在在ajax调用中是否需要考虑Safari的变化?
答案 0 :(得分:18)
更新:旧答案在Firefox中不起作用。
Firefox在空文件字段(而不是其他浏览器中的File对象)上为FormData.get()
返回空字符串。因此,在使用旧的解决方法时,空<input type="file">
将像空<input type="text">
一样发送。不幸的是,在创建FormData对象后,无法区分空文件和空文本。
请改用此解决方案:
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')
})
对于Rails(rails-ujs / jQuery-ujs):https://gist.github.com/ypresto/cabce63b1f4ab57247e1f836668a00a5
旧答案:
过滤FormData(在Ravichandra Adiga的答案中)更好,因为它不会操纵任何DOM。
但是the order of parts in FormData is guaranteed to be the same order to input elements in form,根据<form>
规范。如果有人依赖这个规范,它可能会导致另一个错误。
下面的代码段将保留FormData订单和空白部分。
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/
对于Rails,请参见此处:https://github.com/rails/rails/issues/32440#issuecomment-381185380
(注意:iOS 11.3&Safari的Safari存在此问题,但11.2不存在。)
答案 1 :(得分:5)
对于解决方法,我使用jQuery remove()方法从DOM中完全删除输入类型文件。
$("input[type=file]").each(function() {
if($(this).val() === "") {
$(this).remove();
}
});
答案 2 :(得分:5)
自Webkit build r230963起,此问题已在Webkit中得到解决。我下载并运行该构建并确认问题已解决。不知道哪个公共版本可用于包含此修复程序的Safari。
答案 3 :(得分:2)
我参与了Perl程序中似乎相同的问题
解决方法是在分配formdata之前删除表单元素:
$('#myForm').find("input[type='file']").each(function(){
if ($(this).get(0).files.length === 0) {$(this).remove();}
});
var fData = new FormData($('#myForm')[0]);
...
答案 4 :(得分:1)
var fileNames = formData.getAll("filename[]");
formData.delete("filename[]");
jQuery.each(fileNames, function (key, fileNameObject) {
if (fileNameObject.name) {
formData.append("filename[]", fileNameObject);
}
});
试试这个!!
答案 5 :(得分:0)
这对我有用,可以检查输入字段是否为空。如果为空,请在创建FormData之前禁用输入字段。创建FormData之后,删除“ disabled”属性。与其他答案的区别在于,我搜索“ input [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);