問題描述
目前我正在開發一個允許用戶將文件上傳到 Firebase 存儲的頁面.在 Android 上通過 Google Chrome 打開網站并從標準 HTML 文件輸入中選擇要上傳的文件時,它使用 Android 的本機文件選擇器.
Currently I'm working on a page that allows users to upload a file to Firebase Storage. When opening the site through Google Chrome on Android and selecting a file for upload from a standard HTML file input, it uses Android's native file chooser.
在大多數情況下,用戶會選擇存儲在設備本地的文件,但文件選擇器也會顯示他們的 Google 云端硬盤文件,并且當前不會阻止用戶選擇其中一個文件.該文件在 Javascript 中作為 File 對象返回,但是當嘗試上傳到 Firebase 存儲時,它會引發錯誤:net::ERR_UPLOAD_FILE_CHANGED"并最終超出其重試限制.
In most cases, a user would choose a file stored locally on the device, but the file chooser also shows their Google Drive files and a user currently isn't prevented from selecting one of those files. The file is returned as a File object in Javascript, but when the upload to Firebase Storage is attempted it throws the error: "net::ERR_UPLOAD_FILE_CHANGED" and eventually exceeds it's retry limit.
為了防止用戶混淆,我想阻止用戶在 Android 的文件選擇器中選擇 Google Drive 文件,或者至少認識到它無法上傳并警告用戶.
To prevent confusion for the user, I'd like to prevent the user from selecting a Google Drive file in Android's file chooser, or at the very least recognize that it can't be uploaded and warn the user.
我考慮檢查輸入元素返回的 File 對象,但沒有任何跡象表明可以從 Google Drive 文件中區分本地文件.
I considered checking the File object returned by the input element, but there isn't any indication to tell a local file from a Google Drive file.
<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);
...
}
推薦答案
我不知道如何阻止文件選擇器顯示這些文件,我懷疑沒有,但是如果您的代碼可以很容易地檢查將能夠通過嘗試讀取將其發送到您的服務器.
I don't know a way to prevent the file picker to show these files, and I suspect there is none, but you can check quite easily if your code will be able to send it to your server by trying to read it.
我們可以嘗試只讀取第一個字節,而不是讀取整個文件,方法是對 File 對象進行切片.然后閱讀它,我們可以簡單地調用它的 arrayBuffer()
方法 將返回一個 Promise,要么在文件有效時解析,要么在我們無法訪問文件時拒絕:
Instead of reading the whole file, we can try to read only the first byte, by slicing the File object. Then to read it, we can simply call its arrayBuffer()
method which will return a Promise, either resolving when the File is valid, or rejecting if we can't access the file:
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">
請注意,即使存儲在磁盤上的文件也可能被用戶修改,因為他們確實在您的網站上選擇了它,在這種情況下,上傳仍然會失敗.要處理這種情況,您只需執行完全相同的測試即可.
Note that even Files stored on disk may be modified by the user since they did pick it in your website, in that case, the upload would still fail. To handle this case too, you'd just have to perform the same exact test.
還請注意,Blob.arrayBuffer()
是相當新的,可能需要一個 polyfill,它很容易在 Internet 上制作或找到.
Note also that Blob.arrayBuffer()
is quite recent and may require a polyfill, which is easily made or found on the internet.
這篇關于防止 HTML 文件輸入在使用 Android 的本機文件選擇器時選擇 Google Drive 中的文件的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!