简体   繁体   English

Flask send_file function 由内联 JS 触发但实际上并未返回 send_file

[英]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.我不是 web 开发人员,也从未有过关于该主题的正式说明,所以我只是靠耳朵玩,并使用任何使它起作用的东西。 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.我正在使用 Flask 创建一个网站,当您传递某些信息时,它将返回一个包含您请求的文件的.zip 文件。 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.但是,该网站需要下载文件并对文件执行一些其他处理,因此这是一个耗时的过程,并且当我在 heroku 上托管我的应用程序时会超时。

To bypass this problem, I used the method described here: Flask is not render_template before executing long function为了绕过这个问题,我使用了这里描述的方法: Flask is not render_template before execution long function

Using that post as a guide, my code looks something like this:使用该帖子作为指南,我的代码如下所示:

app.py应用程序.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等待。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.有了这个,当我向long_function提交GET请求时,我立即得到一个有效的响应,即渲染waiting.html模板。 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.同时,在模板渲染的时候,JS脚本发送带有相应信息的POST请求,从而绕过了超时错误。

The issue is that the.zip file is never sent back to me upon the completion of the long task.问题是 .zip 文件在完成长任务后永远不会发回给我。 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. Flask进程显示JS脚本发出的POST请求是有效的,测试时可以得到POST请求返回重定向function到另一个Z572D4E421E5E6B9BC12D815E8A027。 Also, the.zip file is generated correctly and the files are downloaded and processed correctly as well.此外,.zip 文件生成正确,文件下载和处理也正确。 Neither Flask nor Python raise any errors either. Flask 和 Python 都不会引发任何错误。

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.我猜测它与 JS 有关系,但我的 JS 知识几乎不存在,正如我之前所说,web 开发并不是我过于熟悉的东西。 I know that there are other options to run background processes like Celery, but I want to keep this as simple as possible.我知道还有其他选项可以运行后台进程,例如 Celery,但我希望尽可能简单。

What am I missing to get Flask to return my.zip?为了让 Flask 返回 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.感谢这篇文章Flask 作为附件发送文件不起作用,我能够弄清楚发生了什么。

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 .由于 POST 请求是使用 JS 通过浏览器发出的,因此 Flask 正在发送 .zip 文件作为对使用 JS 通过浏览器发出的请求的响应。 Thus, I needed to download the file using the JS response.因此,我需要使用 JS 响应下载文件。 I was able to pull it off using the answer from this post Prompt file download with XMLHttpRequest我能够使用这篇文章的答案Prompt file download with XMLHttpRequest 来完成它

As a result, the script in my waiting.html now looks like this:结果,我waiting.html中的脚本现在看起来像这样:

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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