Downloading resources in HTML5 a[download] may not work as expected
HTML anchor tag can’t download resources from a different origin, learn how I fixed this in my GIF app
HTML5 allows us to add a download
attribute with an optional value to indicate that the resource should be downloaded onto the user’s device.
However, as of late 2018, clicking the link won’t trigger a download if the resource to be downloaded wasn’t served from the same origin or same server so to say. Apparently, this restriction is a security measure.
Attackers may exploit your users by planting malicious download links into your website, so this is a security measure by the browser guys to prevent that.
Quick example
A hyperlink on https://www.facebook.com
cannot download an image(or any resource) that was served from https://www.google.com
. They are not of the same origin 🤷🏿♂️
A possible use case scenario
This was a big issue while I was building a simple GIF app that uses the Giphfy translate API to convert some text into a GIF.
In turn, I wanted the user to be able to download the GIF once it loads but I couldn’t! because the GIF simply wasn’t severed from the same origin as my GIF app. You can check it out here.
Solution1: Data URIs
Basically, a data URI is a base64 encoding of a resource, this means you don’t need to link to an external resource, the text itself is the resource 🙂.
Here is what it looks like
That gibberish text will be way more than that if the file is large. I recommend using the second solution though.
Back to the GIF app!
To incorporate this idea of data URIs, this means we have to convert the file — remote file in this case — into a data URI.
As usual, I ran to npm to search for a package that can help convert my remote GIFs into a data URI. Pweeeeh! After testing about four of them, image-data-uri worked well for me 😘 That’s not all though!
You’ll have a create a link and programmatically click it to get the file downloaded.
I created a react component to do just that, it takes in URL, once clicked and a filename as prop
.
Once clicked:
- It fetches and converts the resource into a data URI
- creates an anchor tag, sets the
href
and clicks the link
Solution 2: Blob (A better solution)
Instead of converting the resource to base64 we can convert it into a blob URL instead. This seems to be the perfect solution.
I totally recommend this using blob over data URI
Thanks for reading 🙂Don’t forget to share if this helped you in any way.
You can catch me on Twitter @MarvinJudeHK
The Gif app is on Github
👋🏿👋🏿👋🏿👋🏿👋🏿👋🏿