1

I'm trying to create an API endpoint that accepts several files (that's why I need POST request, not GET request) and responds with another file. I want browser to present a "save as..." dialog (or just start downloading).

Here's a demo code that doesn't work (Flask):

@app.route('/api', methods=['POST'])
def api():
    return send_file('./sample.txt', as_attachment=True)

I can see proper response headers, but nothing happens in the browser:

HTTP/1.0 200 OK
Content-Disposition: attachment; filename=sample.txt
Content-Length: 612
Content-Type: text/plain; charset=utf-8

If I remove methods=['POST'] from endpoint and issue a GET request to it, it works fine, the browser asks if I want to save this file.

What am I doing wrong or it's just how things are (Content-Disposition ignored for POST responses?)

  • My guess is that browser downloads files by default only from `GET` request. You need to fix it in the client side. For example see [this question](https://stackoverflow.com/questions/51993596/post-request-that-returns-a-download-file) or [this example](https://nehalist.io/downloading-files-from-post-requests/) – Vigen Apr 07 '21 at 13:13
  • Your solution works, post it as answer) This still seems like a hack though – Alexey Kuzmichev Apr 08 '21 at 08:19
  • Not sure that browser behavior standardized for this case, so it will be hard to find clean solution) – Vigen Apr 08 '21 at 13:03

1 Answers1

1

Seems browser shows pop-up for the download, only for the GET requests. But there is a way to show it from client side. Something like this:

document.getElementById('download').addEventListener('click', function () {
  var content = document.getElementById('content').value;
  var request = new XMLHttpRequest();
  request.open('POST', '/api', true);
  request.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8');
  request.responseType = 'blob';

  request.onload = function() {
    if(request.status === 200) {
      var filename = 'sample.txt';

      // The actual download
      var blob = new Blob([request.response], { type: 'text/plain' });
      var link = document.createElement('a');
      link.href = window.URL.createObjectURL(blob);
      link.download = filename;

      document.body.appendChild(link);

      link.click();

      document.body.removeChild(link);
    }

    // some error handling should be done here...
  };

  request.send('content=' + content);
});

More details in this question and in this post

Vigen
  • 483
  • 6
  • 12