更新:从Webkit build r230963开始,这个问题已经在Webkit中得到了解决。
===========
自从最近在macOS和iOS上更新Safari11.1,以及在Safari Technology Preview 11.2中,当input[type=file]
字段没有选择文件时,我的web应用程序中的$.ajax
调用就会失败(这在我的表单中不是必需的)。如果字段确实选择了文件,则不会失败。
ajax
的error
回调运行,Safari控制台包含以下消息:Failed to load resource: The operation couldn’t be completed. Protocol error
。我是HTTPS和提交到同一个域(和服务器)上的位置也通过HTTPS。
在11.1更新之前,当没有选择任何文件时,提交的$.ajax
调用是正常的。Chrome和Firefox的最新版本没有问题。
我的代码的相关部分:
输入:
Browse... <input id="file-upload" type="file" name="image" accept=".jpg,.jpeg">
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 }
});
作为一种临时(希望)解决方案,我检测到一个空文件字段,并在ajax
调用之前将其从formData
中删除,一切都按预期/之前进行:
$("input[type=file]").each(function() {
if($(this).val() === "") {
formData.delete($(this).attr("name"));
}
});
我是不是做错了什么,是Safari有问题,还是Safari的变化需要在ajax调用中解决?
发布于 2018-04-25 03:09:44
从Webkit build r230963开始,这个问题已经在Webkit中得到了解决。我下载并运行了该构建,并确认问题已解决。不知道何时才能为包含此修复的Safari提供公开版本。
发布于 2018-04-14 10:55:45
更新:旧答案在火狐中不起作用。
Firefox在空文件字段(而不是其他浏览器中的文件对象)上返回,只返回空字符串 for FormData.get()
。因此,在使用旧的解决方法时,将像发送空<input type="text">
一样发送空<input type="file">
。不幸的是,在创建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>
规范。如果有人依赖此规范,可能会导致另一个bug。
下面的代码片段将保持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有这个问题,但11.2没有。)
发布于 2018-04-07 23:33:47
为了解决这个问题,我使用jQuery remove()方法从DOM中完全删除了输入类型文件。
$("input[type=file]").each(function() {
if($(this).val() === "") {
$(this).remove();
}
});
https://stackoverflow.com/questions/49614091
复制相似问题