使用 Android 的本机文件选择器时,防止 HTML 文件输入选择 Google Drive 中的文件

J B*_*wer 13 javascript google-chrome firebase google-drive-api firebase-storage

目前我正在处理一个允许用户将文件上传到 Firebase 存储的页面。在 Android 上通过 Google Chrome 打开网站并从标准 HTML 文件输入中选择要上传的文件时,它使用 Android 的本机文件选择器。

在大多数情况下,用户会选择存储在设备本地的文件,但文件选择器还会显示他们的 Google 云端硬盘文件,并且当前不会阻止用户选择这些文件之一。该文件在 Javascript 中作为 File 对象返回,但是当尝试上传到 Firebase Storage 时,它​​会抛出错误:“net::ERR_UPLOAD_FILE_CHANGED”并最终超过它的重试限制。

为了防止用户混淆,我想阻止用户在 Android 的文件选择器中选择 Google Drive 文件,或者至少认识到它无法上传并警告用户。

我考虑过检查 input 元素返回的 File 对象,但没有任何迹象表明本地文件与 Google Drive 文件。

<input type="file" id="upload_input" class="hide"/>
Run Code Online (Sandbox Code Playgroud)
$("#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);

  ...

}

Run Code Online (Sandbox Code Playgroud)

Kai*_*ido 2

我不知道有什么方法可以阻止文件选择器显示这些文件,而且我怀疑没有,但您可以很容易地检查您的代码是否能够通过尝试读取它来将其发送到您的服务器。

我们可以尝试通过切片 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?
    } );
};
Run Code Online (Sandbox Code Playgroud)
<input type="file">
Run Code Online (Sandbox Code Playgroud)

请注意,即使存储在磁盘上的文件也可能被用户修改,因为他们确实在您的网站中选择了它,在这种情况下,上传仍然会失败。要处理这种情况,您只需执行相同的测试即可。

另请注意,这Blob.arrayBuffer()是最近出现的,可能需要一个polyfill,它很容易制作或在互联网上找到。