Skip to content Skip to sidebar Skip to footer

Downloading A File (or Handling An HTTP Error) On Click

I have a button on my page that, when clicked, will try to go out and download a file from a given URL on a different domain than my page's domain. Sometimes, that download URL wi

Solution 1:

You can use XMLHttpRequest(), with error event attached to request resource. If request is not successful, error should be handled at error event handler of XMLHttpRequest().

You could alternatively use fetch() to achieve same result.

Set .responseType to "blob" at XMLHttpRequest or return response.blob() at fetch(). Create a new Blob with type set to "application/octet-stream", call window.open() with URL.createObjectURL() as parameter where Blob is parameter to .createObjectURL(), which should open Save File dialog.

You can chain .catch() to fetch() to handle errors.

<body>
  <a href="#" data-link="file.txt">download file.txt</a>
  <a href="#" data-link="http://stackoverflow.com">download stackoverflow.com</a>
  <script>

    var request = (path) =>
      fetch(path)
      .then(response => response.blob())
      .then(blob => window.open(
        URL.createObjectURL(
          new Blob([blob], {
            type: "application/octet-stream"
          })
        ), "_self"))
      // handle request error
      .catch((err) => {console.log(err); throw err});

    var a = document.querySelectorAll("a");
    for (let link of a) {
      link.onclick = (e) => {
        e.preventDefault();
        request(e.target.dataset.link)
        .catch((err) => {
          alert(err.message + "\ndownload of " + e.target.dataset.link + " error")
        })
      }
    }
  </script>
</body>

plnkr http://plnkr.co/edit/J40cPoLJ2WwESRzsSRhL?p=preview


Alternatively using <a> element, download attribute to suggest file name at Save File dialog

<body>
  <a href="#" data-link="file.txt">download file.txt</a>
  <a href="#" data-link="http://stackoverflow.com">download stackoverflow.com</a>
  <script>

    var request = (path) =>
      fetch(path)
      .then(response => response.blob())
      .then(blob => {
        var type = blob.type.split("/").pop();
        type = type === "plain" ? "txt" : type;
        var d = document.createElement("a");
        d.className = "download";
        d.download = "file-" + new Date().getTime() + "." + type;
        d.href = URL.createObjectURL(blob);
        document.body.appendChild(d);
        d.click();
        d.parentElement.removeChild(d);
      })
      // handle request error
      .catch((err) => {console.log(err); throw err});

    var a = document.querySelectorAll("a[href='#']");
    for (let link of a) {
      link.onclick = (e) => {
        console.log(e)
        e.preventDefault();
        request(e.target.dataset.link)
        .catch((err) => {
          alert(err.message + "\ndownload of " + e.target.dataset.link + " error")
        })
      }
    }
  </script>
</body>

Solution 2:

For handling the download of the file, the download attribute could be a solution (with polyfill).

But for the handling the HTTP errors in my opinion the best solution is using some back-end proxy which will check the HTTP headers and also will force the browser to download a specific file.


Post a Comment for "Downloading A File (or Handling An HTTP Error) On Click"