How to download a file from the back-end?

Hi,

I have a server back-end that serve my Ember app and some data in different form: Sometimes as JSON data, sometimes as files I want the browser download.

My question is: How can I make my browser save my files from back-end?

When I try to request a file by its back-end url, I have my Ember app with a route corresponding to my file, but not my file.

When I try to request a file using Ember.$.get(), for example, I have my file content in the ajax response, the response header seems well formed (to do a download with nice content-type and content-disposition), but I don’t find any way to make the browser show the download dialog.

Any idea?

Did you see https://github.com/PixelsCommander/Download-File-JS ?

window.downloadFile(get(exp, 'url'));

I didn’t know it. I just tried it and it gives me the same results I had until now.

When the <a href=“urlFile” download=“filename”> is recognized by the browser, it record a html file in which I found my app default view. When it is not, it open my app default view in the browser.

May it be possible to dynamically override the Ember url handling to make the browser really do a request to the backend for some choosen routes?

Or anything else…

did you try handle click on link with jQuery and inside handler call window.downloadFile? Is url correct?

Yes. That was my test. And I think downloadFile() do its job.

Example:

My Ember app is on http://localhost:4200/ . I have a http://localhost:4200/foo/ view in which I have a link to download a file on “/foo/bar” (that mean http://localhost:4200/foo/bar") My server backend correctly serve the file.

Surprisingly a call to …

Ember.$.get(‘/foo/bar’, function (content) {…})

… retrieve the content of the zip file. That mean that a request with Ember.$.get() ignore the Ember URL handling/routing. But, by this way, I don’t know how to force the browser to do a file download.

All others way I tried …

  • <a href=“/foo/bar” [download=“filename”]>
  • window.location
  • try to download via a iframe
  • and window.downloadFile() with your download-file-js library

… show or download an html document corresponding to an Ember’s http://localhost:4200/foo/bar route (that do not exists by the way)

I can’t believe nobody had the same problem. Downloading a file on the backend server is a so common task.

Anyway, thank you for your help.

This might seem stupid (and maybe it is) but try calling the server again, in the ajax success callback, using window.location, with the same path used for the ajax request.

I’ll check case with related path and dowload.js tomorrow

And now – as I understand – your url handled with router. Then if your backend send correct headers ( to save file ) – try just add ‘target=“_blank”’ to your links — that’s prevent route handling. And browsers close tabs/windows after saving file – just try

When I try to change window.location to /foo/bar in ajax success callback, my browser show my Ember application with the route “http://localhost:4200/foo/bar”.

But no download :cry:

I tried with a link like this:

<a href=“http://localhost:4200/foo/bar” download=“test” target=“_blank”>download</a>

I download a file, but not the one I whant. The downloaded file content is the the HTML of the a default “foo.bar” view.

Are you using ember-cli? or you test on real server?

I am using ember-cli for client side, and more precisely “Sane Stack” for the entire system.

I just found a way to have my download done: Using a POST request in a dynamically built form instead of just GET my url. By this way, Ember do not handle my url, and it works.

The thing I don’t understand is why a Ember.$.get() get a response from my backend (it’s a GET request too) and not the other ways?

… I guess there is maybe a way by preventing transitions, but I’m not sure.

Using POST seems like a decent solution. The reason that Ember.$.GET works is that it’s using AJAX rather than a normal, direct request.

I had the exact same question you did when you posted. I was able to partially solve the problem by using https://github.com/eligrey/FileSaver.js/ with the Ember.$.GET. I’m able to successfully retrieve text files, but binary files are being problematic. They get saved but as text files with the byte content.

FileSaver.js seems to be a nice solution, as nice as Download-File.js, but there are twice based on more or less recents features (download attribute or saveAs() method)

At the end, I have to make a large public website, and I prefer to not have to come back on my work because some people used to use old browsers.

The POST solution should work on all browsers without any bad bias. My time is costly, so for now, I prefer this solution because I don’t find any better.

But, to be fully in “Ember spirit”, I keep my question open. I really think, there is a way to do what I wanted in a nicer way, maybe by using Ember transition preventing. Or maybe I’m wrong. For now, I don’t have a good enough skill with Ember. I consider I found something like a trick more than a nice solution.

It could be usefull for people and for Ember to have a real Ember recipe to do this than a kind of “do-it-yourself” for a such common need.

:wink:

I had to solve a similar problem in a SANE app. After researching the options I decided to serve the files directly from sails.

Public static files are served directly from the sails asset directory.

/<path to file>/<file name>

Dynamic csv files of exported data are created by a download method on the controller of the model. It executes a find, does some transforms, and then uses a custom response and json2csv to generate and return the file. The uri is derived from environment configuration items and the application state.

/api/v1/<model>/download?<where criteria>

Protected static files are served by a Download controller that streams files from a protected folder.

/api/v1/download?<file>

The links only work when ember is built and served from the assets directory. They won’t work during development while running the application with sane.

ember build --environment=production --output-path=../server/assets/.

Its not the Ember way but it works. I hope this is helpful.

Guys, how about streaming generated file from backend(laravel) to ember(client side). I have 3 types of files - csv,xls and pdf. The only way I can make it work is downloading the file, then sending filepath to ember and window.open it. After that I make second request to delete exported file, but at that moment I’m not sure the file is downloaded. I can’t find solution anywhere. If somebody can help,I will be very grateful. :slight_smile:

One thing that you can do, is to render just a simple <form>, which points to your file generating endpoint. And from this endpoint, you can stream your file. For example, in Rails you can do:

def download_report
  # Generate report
  send_data report, filename: 'My awesome report.pdf', disposition: 'attachment'
end