简体   繁体   中英

Flask send_file function triggered by inline JS but does not actually return the send_file

A bit of context about me and the problem. I'm not a web developer and never had formal instruction on the topic so I'm playing it by ear and using whatever makes it work. I'm using Flask to create a website that when you pass certain information, it will return a.zip file that contains the files you requested. However, the website needs to download and perform some other processes on the files, so it is a time consuming process and it times out when I host my app on heroku.

To bypass this problem, I used the method described here: Flask is not render_template before executing long function

Using that post as a guide, my code looks something like this:

app.py

@app.route('/long_function/<var1>/<var2>', methods=['GET', 'POST'])
def long_function(var1, var2):
    if request.method == 'POST':
        #Long task...
        return send_file(data, as_attachment=True, attachment_filename='data.zip')

    if request.method == 'GET':
         return render_template('waiting.html', var1=json.dumps(var1), var2=json.dumps(var2), return_to=json.dumps('/home')

waiting.html

<script>
    var request = new XMLHttpRequest();
    request.open('POST', '/long_function/'+{{ var1|safe }} +'/'+ {{ var2|safe }});


    request.onload = function() {
      if (request.status === 200) {
        // long process finished successfully, redirect user
        window.location = {{ return_to|safe }};
      } else {
        // ops, we got an error from the server
        alert('Something went wrong.');
      }
    };

    request.onerror = function() {
      // ops, we got an error trying to talk to the server
      alert('Something went wrong.');
    };

    request.send();
</script>

With this, when I submit the GET request to the long_function, I immediately get a valid response, which is to render the waiting.html template. At the same time, when the template is rendered, the JS script sends the POST request with the corresponding information, thus bypassing the timeout error.

The issue is that the.zip file is never sent back to me upon the completion of the long task. The Flask process shows that the POST request made by the JS script is valid, and when testing I can get the POST request to return a redirect function to another url. Also, the.zip file is generated correctly and the files are downloaded and processed correctly as well. Neither Flask nor Python raise any errors either.

I'm guessing that it has something to do with the JS, but my JS knowledge is almost non-existent and as I said before, web development is not something I'm overly familiar with. I know that there are other options to run background processes like Celery, but I want to keep this as simple as possible.

What am I missing to get Flask to return my.zip? Any comments are greatly appreciated!

Thanks to this post Flask send_file as attachment not working I was able to figure out what was going on.

Since the POST request is made through the browser using JS, Flask is sending the.zip file as a response for the request made through the browser using JS . Thus, I needed to download the file using the JS response. I was able to pull it off using the answer from this post Prompt file download with XMLHttpRequest

As a result, the script in my waiting.html now looks like this:

<script>
    var request = new XMLHttpRequest();
    request.responseType = 'blob';
    request.open('POST', '/long_function/'+{{ var1|safe }} +'/'+ {{ var2|safe }});

    function saveBlob(blob, fileName) {
    var a = document.createElement('a');
    a.href = window.URL.createObjectURL(blob);
    a.download = fileName;
    a.dispatchEvent(new MouseEvent('click'));
}


    request.onload = function(e) {
      if (request.status === 200) {
        // long process finished successfully, redirect user
        var blob = e.currentTarget.response;
        saveBlob(blob, 'data.zip')
        window.location = {{ return_to|safe }};
      } else {
        // ops, we got an error from the server
        alert('Something went wrong.');
      }
    };

    request.onerror = function() {
      // ops, we got an error trying to talk to the server
      alert('Something went wrong.');
    };

    request.send();
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM