Javascript 更改后使用AJAX重新上载文件会导致net::ERR_UPLOAD_file_在Chrome中更改
我有一个简单的HTML表单,它通过AJAX将选定的文件发送到API端点 如果我执行以下步骤:Javascript 更改后使用AJAX重新上载文件会导致net::ERR_UPLOAD_file_在Chrome中更改,javascript,ajax,google-chrome,file-upload,Javascript,Ajax,Google Chrome,File Upload,我有一个简单的HTML表单,它通过AJAX将选定的文件发送到API端点 如果我执行以下步骤: 按下上载按钮并发出POST请求以上载文件 更改文件系统(在文本编辑器中)上的选定文件,而无需在文件选择器中再次拾取该文件 再次按下上载按钮,并作为第二个POST请求进行设置 Chrome将在第二次请求失败时出错:net::ERR\u UPLOAD\u FILE\u CHANGED。请注意,如果您在首次上载之前更改了文件,则将毫无问题地上载该文件。只有在首次成功上载后更改文件时,才会在第二次上载时发生此错
net::ERR\u UPLOAD\u FILE\u CHANGED
。请注意,如果您在首次上载之前更改了文件,则将毫无问题地上载该文件。只有在首次成功上载后更改文件时,才会在第二次上载时发生此错误。我正在用CSV文件进行测试,并在文本编辑器中更改它们
似乎没有办法孤立这一错误
这有什么办法吗
如果没有,是否可以捕获此特定错误,并向用户显示有意义的消息。承诺中Fetch返回的错误没有关于此的特定信息。在浏览器开发控制台中,我只能看到ERR\u UPLOAD\u FILE\u CHANGED
我敢肯定,大约一年前(2019年初),这并没有任何问题,因为重新上传更改的文件的可能性,在我们的UI流中很好地发挥了作用。现在我们需要强制用户再次选择文件。所以我假设这是在最近的chrome更新中引入的
以下是代码的简化片段:
<html>
<head>
<script type='text/javascript'>
document.addEventListener("DOMContentLoaded", function(){
const button = document.querySelector('#btnSubmit');
button.addEventListener('click', () => {
const form = new FormData(document.querySelector('#theForm'));
const url = '/my-api'
const request = new Request(url, {
method: 'POST',
body: form
});
fetch(request).then(function() {
console.log("ok");
}).catch(function(err) {
console.log(err);
});
});
});
</script>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post" id='theForm'>
<input type="file" name="csvfile" id="csvfile" value="" /></td>
<input type="button" name="uploadCSV" value="Upload" id='btnSubmit'/>
</form>
</body>
</html>
document.addEventListener(“DOMContentLoaded”,function()){
const button=document.querySelector(“#btnSubmit”);
按钮。addEventListener('单击',()=>{
const form=new FormData(document.querySelector(“#theForm”);
常量url='/my api'
const request=新请求(url{
方法:“POST”,
正文:表格
});
获取(请求).then(函数(){
控制台日志(“ok”);
}).catch(函数(err){
控制台日志(err);
});
});
});
编辑:bug在bugs.chromium.org上被标记为WontFix:我只需在点击上传按钮和重置表单值之间检查file.lastModified
更好的解决方案是将文件读入ArrayBuffer并上传。我使用javascript文件读取器获得了一个更具描述性的错误。更改文件并第二次按下按钮后,FileReader会抛出一条更具描述性的消息:
DOMException:无法读取请求的文件,通常是由于获取文件引用后出现的权限问题。
至少这是一个可以捕获并显示给用户的错误,因此用户知道需要重新选择文件
以下是片段:
<html>
<head>
<title>Test</title>
<script type='text/javascript'>
document.addEventListener("DOMContentLoaded", function(){
const button = document.querySelector('#btnSubmit');
button.addEventListener('click', () => {
let inputElement = document.getElementById('csvfile');
for (let i = 0; i < inputElement.files.length; i++) {
const file = inputElement.files[i];
console.log(file);
const reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
console.log(evt.target.result);
}
reader.onerror = function (err) {
// read error caught here
console.log(err);
console.log(err.target.error);
}
}
});
});
</script>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post" id='theForm'>
<input type="file" name="csvfile" id="csvfile" value="" />
<input type="button" name="uploadCSV" value="Upload" id='btnSubmit'/>
</form>
</body>
</html>
试验
document.addEventListener(“DOMContentLoaded”,function()){
const button=document.querySelector(“#btnSubmit”);
按钮。addEventListener('单击',()=>{
让inputElement=document.getElementById('csvfile');
for(设i=0;i
目前似乎没有办法解决这个问题(2020年6月)。Chromium上有一个打开的bug:
否,如果用户更改了文件,则该文件已经是另一个文件,因此在没有用户明确的用户操作的情况下,您无法(不应该)访问该文件,否则这将是一个安全问题 用户上传文件时,可以将其保存在内存中
document.getElementById('fileInput')。addEventListener('change',function(){
saveFileConentInMemory(this.files[0].arrayBuffer());
});
当用户按下“发送”按钮时,只需从内存中获取内容并发送即可
按钮。addEventListener('单击',()=>{
const file=getFileContentFromMemeory();
发送(文件);
})
是的,您不能确定是否发送了文件的最新版本,但应确保发送了上载的内容
此外,您还应该了解读取文件的内存消耗和异步API(因此即使在内存中写入内容,也可能会出现有关更改内容的错误)一个快速的解决方法是在AJAX调用中包含一个
complete
参数(或总是被调用的任何等价的finally
调用)并添加重置表单的代码。我注意到再次附加文件可以解决这个问题。虽然我理解这不是问题的真正解决方案,但它确实提供了处理,或者说避免了错误
这样,如果用户出于任何原因需要重新上传文件,他们将不得不再次选择该文件
示例如下:
$.ajax({
url: this.action,
type: this.method,
data: this.data,
success: function (response) {
// success scenario
},
error: function (result) {
// error scenario
},
complete: function (data) {
$('#uploadForm')[0].reset(); // this will reset the form fields
}
});
只需在提示消息或处理
$('#file').val("");
$("#id_of_your_file_input").click(function(){
$("#id_of_your_file_input").val('');
});