You Can’t Prompt a File Download With the Content Disposition Header Using Axios (XHR). Sorry.
If you’re reading this article, I’m really sorry. I can feel your desperation. You know, you BELIEVE, that using the content disposition header should work in order to trigger a file download after making a call to an api with axios. But it doesn’t. Not for you. Not for anyone. And it never will. Never. Ever. Never, ever, ever. So, I’m sorry. Give up now.
(paraphrased from a slack message of @glebec)
i.e. It doesn’t owe you a fucking thing.
Why I have the misfortune of knowing this
Here’s what I wanted to happen:
- A user hits the submit button in my SPA (yes, an actual SPA)
- The submit button triggers a request via axios
- An xml string is generated on the backend, based on the application’s state, and then sent back to the client
- The user sees a download dialogue with the correct file name and file type in the box and can download the response data as a file. Yay.
Here’s how I thought I could make it happen:
- Easy! Just set the Content-Disposition header on the response to “attachment; filename=myCoolFile.xml”
- Simple! Just send the data back.
- User just magically sees the download dialogue and I get a raise.
Here’s what didn’t happen:
- EXACTLY FU***NG THAT!!!
Why why why why why why why why why why why
So, my server’s response had the content-disposition header of attachment.
"Content-Disposition": attachment; filename="cool.xml"
When I made the GET request directly via the browser, it worked perfectly. I saw the download dialogue box, the right file name, everything. I had everything!
That’s because, as I learned, the browser received that Content Disposition header and knew to display the content as an attachment and prompt the download.
It’s like the browser hit a volleyball over a net and then the server spiked it right back onto its face and it was like, oh I should do something about this.
But when I made the GET request via axios, the browser saw the header and the content-disposition set to attachment, but did not trigger the download dialogue because that wasn’t its job.
It’s like axios and the browser were both playing volleyball, but instead of playing, the browser was sticking its head up its own ass as far as it could go. (OK, maybe being a little unfair to the browser here, but you get it).
The Sad Thing You Might Have to Do
It’s like Jay from Chicago Tech Slack said:
I’m sorry there’s not something better, Emily. I know you’ve been struggling with this for at least two weeks now.
I unfortunately still believe that there might be a way to make some of this magic happen on the server side so I don’t have to do that thing above here. Maybe generate a file, print it out, and then slap the user on the face with it via a man in a bear suit as part of a singing telegram service. I don’t know.
The moral of the story
This specific way to trigger a file download doesn’t work. It’s not your fault. It’s not my fault. It’s [fill-in-the-name-of-some-historical-character-you-don’t-like]’s fault, and they’re dead.
Find another way to make this happen.
P.S. Gabriel Lebec also suggested looking into creating a data URI on the client side, which seems like it could be a solution for downloading smaller files.