目前我正在做一个允许用户上传文件到Firebase存储的页面。当通过Android上的Google Chrome浏览器打开网站,并从标准的HTML文件输入中选择要上传的文件时,它使用Android的本地文件选择器。
在大多数情况下,用户会选择存储在设备本地的文件,但文件选择器也会显示他们的Google Drive文件,目前并不妨碍用户选择其中的一个文件。文件在Javascript中以File对象的形式返回,但当尝试上传到Firebase Storage时,会抛出错误。"net::ERR_UPLOAD_FILE_CHANGED "并最终超过了它的重试限制。
为了防止用户的困惑,我希望防止用户在Android的文件选择器中选择Google Drive文件,或者至少识别出它不能被上传并警告用户。
我考虑过检查输入元素返回的File对象,但没有任何指示来区分本地文件和Google Drive文件。
<input type="file" id="upload_input" class="hide"/>
$("#upload_input").change(function(e) {
if (!e.target.files) {
return;
}
const file = e.target.files[0];
uploadFile(file);
});
uploadFile(file) {
...
const storageRef = firebase.storage().ref();
const fileRef = storageRef.child(`${userID}/uploads/${file.name}`);
const uploadTask = fileRef.put(file);
...
}
我不知道有什么方法可以阻止文件选取器显示这些文件,我怀疑没有,但你可以很容易地检查你的代码是否能够通过尝试读取它来将其发送到服务器。
我们可以尝试只读取第一个字节,而不是读取整个文件,通过对File对象进行切片。然后读取它,我们可以简单地调用它的 arrayBuffer()
办法 这将返回一个Promise,要么解决当文件是有效的,或拒绝,如果我们不能访问该文件。
const inp = document.querySelector('input');
inp.onchange = (evt) => {
const file = inp.files[ 0 ];
file.slice( 0, 1 ) // only the first byte
.arrayBuffer() // try to read
.then( () => {
// success, we should be able to send that File
console.log( 'should be fine' );
} )
.catch( (err) => {
// error while reading
console.log( 'failed to read' );
inp.value = null; // remove invalid file?
} );
};
<input type="file">
请注意,即使是存储在磁盘上的文件 也可能被用户修改,因为他们确实在你的网站上选择了它,在这种情况下,上传仍然会失败。要处理这种情况,你只需要执行同样的测试。
还要注意的是 Blob.arrayBuffer()
是很新的,可能需要一个polyfill,这个很容易制作或在网上找到。
它处理的是文件的修改属性,输入标签得到的是一个同名的文件,但它的修改属性却没有改变。
我得到的唯一解决方案是--------。
你需要在用户点击时重置输入标签的输入字段,因为默认情况下它在点击时是空的。
例如;使用jquery库来重置输入标签。
document.querySelector("#upload_input").addEventListener("click",
function(event){
$("#upload_input").val("");
})