HTML anchor tag download attribute not working in Firefox for jpg and png files

前端 未结 3 1632
感动是毒
感动是毒 2021-01-04 07:03

In my web application I have supported user to upload any type of document (.png, .jpg, .docx, .xls, ... )
I\'m trying to implement download functionality for these do

相关标签:
3条回答
  • 2021-01-04 07:40

    Firefox will handle png and jpeg using default handling, which is to inline them in the document. When clicking a link, even if download attribute is defined, seem to make Firefox think it has a new image ignoring the download aspect of it. This may be a temporary bug.

    Here is a way, admittedly not super-elegant, to get around this problem forcing the image to be interpreted as an octet-stream.

    It does not work inline on Stackoverflow so you have to test it on jsFiddle.

    The code does the following:

    • Scans the document for a-tags.
    • Those which has data-link set will have a common click-handler attached.
    • When clicked the link is extracted from the data-link attribute (href is se to #), loaded as an ArrayBuffer via XHR (CORS requirements applies, not a problem in this case), and is converted to an Object-URL with the Blob set to mime-type octet/stream
    • The Object URL is set as window.location to redirect to this binary data which will make the browser ask user to download the file instead.
    var links = document.querySelectorAll("a"), i = 0, lnk;
    
    while(lnk = links[i++]) {
      if (lnk.dataset.link.length) lnk.onclick = toBlob;
    }
    
    function toBlob(e) {
      e.preventDefault();
      var lnk = this, xhr = new XMLHttpRequest();
      xhr.open("GET", lnk.dataset.link);
      xhr.responseType = "blob";
      xhr.overrideMimeType("octet/stream");
      xhr.onload = function() {
        if (xhr.status === 200) {
          window.location = (URL || webkitURL).createObjectURL(xhr.response);
        }
      };
      xhr.send();
    }
    

    Example tag:

    <a href="#" data-link="image.jpg">Click to download</a>
    

    The drawback is that you'll loose the extension in the filename.

    This is also possible to do using a Data-URL, but a data-url has a 166% overhead compared to using ArrayBuffer and a blob.

    0 讨论(0)
  • 2021-01-04 07:47

    I had a similar problem with firefox not handling the download attribute, even for same-domain files.

    My target files are actually hosted on AWS, so they are cross-domain. I got around this with a same-domain endpoint that downloads the remote file and pipes it to the client.

    const express = require('express')
    const {createWriteStream} = require('fs')
    const downloadVideo = (url) => { return new Promise((resolve, reject) => {
      const filePath = `/tmp/neat.mp4`
      const ws = createWriteStream(filePath)
      request(url, {}, (error, response, body) => {
        if(error) { return reject(error) }
        resolve(filePath)
      }).pipe(ws)
    })}
    
    app.get('/api/download', async (req, res) => {
      const videoPath = await downloadVideo(req.query.url)
      res.sendFile(videoPath)
    })
    

    On the client, I send the file path to the download endpoint to get a blob back, which is then converted to an object url. From there, it's standard download attribute stuff.

    async download(remoteFilePath){
      const a = document.createElement('a')
      const dlURL = `/api/download?url=${encodeURIComponent(remoteFilePath)}`
      const blob = await fetch(dlURL).then(res => res.blob())
      a.href = URL.createObjectURL(blob)
      a.setAttribute('download', 'cool.mp4')
      document.body.appendChild(a)
      a.click()
      a.remove()
    }
    
    0 讨论(0)
  • 2021-01-04 07:56

    As you are using HTML5 attribute, each browser handling differently. So use https://github.com/dcneiner/Downloadify for client side forceful download instead of viewing in browser.

    0 讨论(0)
提交回复
热议问题