简体   繁体   中英

How does download in Google Drive (Web) work?

I am currently implementing a file download in a web application. I was struggling a little with the pop up blocker, the download needs to start immediately after the user interaction, so there cannot be a server round trip. Now I noticed, that Goolge Drive for example allows you to download folders. When you do that, their server first creates a compressed zip file, which takes some time.When the server finished, the download starts immediately without another user interaction.

Now I am wondering how this can be done?

I wrote a function to download a file via url. In your case, you must use ajax request to make a zip file on server then give back url and run below function to download:

function download(url, filename){
    fetch(url)
    .then(resp => resp.blob())
    .then(blob => {
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.style.display = 'none';
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      window.URL.revokeObjectURL(url);
      console.log('your file has downloaded!'); 
    })
    .catch(() => console.log('Download failed!'));
}

Test codepen here: download file via url

I noticed, that Google Drive for example allows you to download folders. When you do that, their server first creates a compressed zip file, which takes some time.

Alternatively, you could request the contents of the directory as json, then loop over the json and download each file as a blob and create a zip file, the only blocking then would be the request to the json, then you could show a status of each file downloaded etc.

Libs to do that:

Snippet example, using vue, s3 etc

async download(bucket) {

  this.$snackbar.show({
    type: 'bg-success text-white',
    message: 'Building Zip, please wait...'
  })

  //..eek fetch all items in bucket, plop into a zip, then trigger download
  // - there is some limits on final filesize, will work around it by disabling download :)

  // resolve objects
  const objects = async(bucket) => new Promise(async(resolve, reject) => {
    let objectStream = await this.state.host.client.listObjectsV2(bucket, '', true)
    let objects = []
    //
    objectStream.on('data', (obj) => {
      if (obj && (obj.name || obj.prefix)) {
        this.$snackbar.show({
          type: 'bg-success text-white',
          message: 'Fetching: ' + obj.name
        })
        objects.push(obj)
      }
    })
    objectStream.on('end', () => resolve(objects))
    objectStream.on('error', (e) => reject(e))
  })

  // get an objects data
  const getObject = (bucket, name) => new Promise((resolve, reject) => {
    this.state.host.client.getObject(bucket, name, (err, dataStream) => {
      let chunks = []
      dataStream.on('data', chunk => {
        this.$snackbar.show({
          type: 'bg-success text-white',
          message: 'Downloading: ' + name
        })
        chunks.push(chunk)
      })
      dataStream.on('end', () => resolve(Buffer.concat(chunks || [])))
    })
  })

  // fetch objects info a zip file
  const makeZip = (bucket, objects) => new Promise(async(resolve, reject) => {
    let zip = new JSZip()

    for (let i in objects) {
      this.$snackbar.show({
        type: 'bg-success text-white',
        message: 'Zipping: ' + objects[i].name
      })
      zip.file(objects[i].name, await getObject(bucket, objects[i].name));
    }

    zip.generateAsync({
      type: "blob"
    }).then(content => {
      this.$snackbar.show({
        type: 'bg-success text-white',
        message: 'Zip Created'
      })
      resolve(content)
    })
  })

  // using FileSaver, download file
  const downloadZip = (content) => {
    this.$snackbar.show({
      type: 'bg-success text-white',
      message: `Downloading: ${bucket.name}.zip`
    })
    FileSaver.saveAs(content, `${bucket.name}.zip`)
  }

  try {
    downloadZip(await makeZip(bucket.name, await objects(bucket.name)))
  } catch (e) {
    this.$snackbar.show({
      type: 'bg-danger text-white',
      message: e.message
    })
    console.error(e)
  }
},

If you want an ugly way to download a directory, fetch the json list then place a bunch of document.createElement('a') on the dom with a.setAttribute("target", "_blank") , but you will get a bunch of "Save As" dialogues open.

How to download multiple images?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM