更新:截至 Webkit build r230963 , 这个问题已经在 Webkit 中解决了。
===========
自从最近在 macOS 和 iOS 上更新 Safari 11.1 以及 Safari Technology Preview 11.2 以来,当 input[type= file]
字段没有选择文件(我的表单不需要)。当字段确实选择了文件时没有失败。
ajax
的error
回调运行,Safari 控制台包含以下消息:加载资源失败:操作无法完成。协议(protocol)错误
。我使用 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 调用中考虑?
最佳答案
更新:旧答案在 Firefox 中不起作用。
Firefox 为 FormData.get()
返回空字符串在空文件字段上(而不是其他浏览器中的 File 对象)。所以当使用旧的解决方法时,清空 <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 有这个问题,但 11.2 没有。)
关于javascript - Safari 11.1 : ajax/XHR form submission fails when input[type=file] is empty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49614091/