【问题标题】:Download file from API从 API 下载文件
【发布时间】:2018-05-10 14:47:50
【问题描述】:

我正在将一个文件从网页发送到 Flask 服务器,对其执行一些转换,然后我想返回转换后的文档以便用户下载它。我有一个按钮,这将发送 POST 请求:

fileUpload: function(file) {
  var formData = new FormData();
  formData.append('file',file);
  var xhr = new XMLHttpRequest();
  xhr.addEventListener("load", () => {
    console.log("asdf");
  });
  xhr.open("POST", "http://localhost:7733/receivedoc");
  xhr.send(formData);
}

然后在服务器上,我做转换,想返回一个文件:

...
#Transformations, save file to the file system
return send_from_directory(app.config['UPLOAD_FOLDER'], filename, as_attachment=True)

但是,我的浏览器没有下载任何文件。没有错误,请求似乎通过了。请求标头是

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en;q=0.9,en-US;q=0.8,hu;q=0.7,cs;q=0.6,sk;q=0.5,de;q=0.4
Connection: keep-alive
Content-Length: 114906
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycEQwQtGAXe1ysM9b
DNT: 1
Host: localhost:7733
Origin: http://localhost:5000
Referer: http://localhost:5000/

以及请求负载:

------WebKitFormBoundarycEQwQtGAXe1ysM9b
Content-Disposition: form-data; name="file"; filename="response.xls"
Content-Type: application/octet-stream


------WebKitFormBoundarycEQwQtGAXe1ysM9b--

response.xls 正是我要下载的文件。怎么下载?

更新 - 尝试实施 Joost 的解决方案。我愿意:

@app.route('/receivedoc', methods=['POST', 'GET', 'OPTIONS'])
@crossdomain(origin='*')
def upload_file():
    if request.method == 'POST':
#TRANSFORMING FILE, then saving below:
            writer = pd.ExcelWriter(filename)
            df_output.to_excel(writer,'Pacing', index=False)
            writer.save()
            return send_from_directory(directory=app.config['UPLOAD_FOLDER'], filename=filename)

    if request.method == 'GET':
        prefixed = [filename for filename in os.listdir(app.config['UPLOAD_FOLDER']) if filename.startswith("PG PEIT")]
        filename = max(prefixed)
        print("what what")
        return render_template_string('''<!DOCTYPE html>
            <html lang="en">
            <head>
            <meta charset="utf-8">
            <title>Your file is ready</title>
            </head>
            <body>
            <form enctype="multipart/form-data" method="post" name="fileinfo">
            <input type="text" name="fname" required />
            <input type="submit" value="request the file!" />
            </form>
            <script>
            function saveBlob(blob, fileName) {
                var a = document.createElement("a");
                a.href = window.URL.createObjectURL(blob);
                a.download = fileName;
                document.body.appendChild(a); // won't work in firefox otherwise
                a.click();
            }
            var form = document.forms.namedItem("fileinfo");
            form.addEventListener('submit', function(ev) {
            var oData = new FormData(form);
            var oReq = new XMLHttpRequest();
            oReq.responseType = 'blob';
            oReq.open("POST", "{{url_for('upload_file')}}", true);
            oReq.onload = function(oEvent) {
                if (oReq.status == 200) {
                var blob = oReq.response;
                var fileName = 'response.xml'
                saveBlob(blob, fileName);
                } else {
                alert("Error " + oReq.status + " occurred")
                }
            };
            oReq.send(oData);
            ev.preventDefault();
            }, false);
            </script>
            </body>
            </html>
            ''')

这会给我一个很好的 .html 响应,但文件仍然无法下载:

我误会了什么?

【问题讨论】:

    标签: python rest flask download


    【解决方案1】:

    这主要是一个javascript问题,python与它没有太大关系。几周前我遇到了同样的问题,所以我决定做一个工作应用程序的小例子。主要技巧是将数据保存在js中,使用数据制作可下载的链接,并让js点击它。

    全功能示例:

    from flask import Flask, render_template_string, request, url_for, send_from_directory
    
    
    app = Flask(__name__)
    
    
    @app.route('/', methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            fname = request.form['fname']
            return send_from_directory('', fname, as_attachment=True)
        return render_template_string('''<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>title</title>
    </head>
    <body>
    <form enctype="multipart/form-data" method="post" name="fileinfo">
      <input type="text" name="fname" required />
      <input type="submit" value="request the file!" />
    </form>
    <script>
    function saveBlob(blob, fileName) {
        var a = document.createElement("a");
        a.href = window.URL.createObjectURL(blob);
        a.download = fileName;
        document.body.appendChild(a); // won't work in firefox otherwise
        a.click();
    }
    
    var form = document.forms.namedItem("fileinfo");
    form.addEventListener('submit', function(ev) {
      var oData = new FormData(form);
      var oReq = new XMLHttpRequest();
      oReq.responseType = 'blob';
      oReq.open("POST", "{{url_for('index')}}", true);
      oReq.onload = function(oEvent) {
        if (oReq.status == 200) {
          var blob = oReq.response;
          var fileName = 'response.xml'
          saveBlob(blob, fileName);
        } else {
          alert("Error " + oReq.status + " occurred")
        }
      };
      oReq.send(oData);
      ev.preventDefault();
    }, false);
    </script>
    </body>
    </html>
    ''')
    
    
    app.run()
    

    【讨论】:

    • 这似乎是一个解决方案,但是,它似乎对我不起作用。当我检查控制台时,我确实在网页上的调用响应中得到了整个 html 部分,但是,下载仍然不会发生。
    • 不,但如果它在 Chrome 中不起作用,那么我需要另一个解决方案。
    • 我刚刚又试了一次。它适用于 Firefox 和 chrome。只需复制示例并查看是否可以运行它。然后从那里回来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2013-12-14
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    相关资源
    最近更新 更多