【问题标题】:Flask send_file not sending file烧瓶 send_file 不发送文件
【发布时间】:2019-05-13 19:23:44
【问题描述】:

我正在使用 Flask 和 send_file() 让人们从服务器下载文件。

我目前的代码如下:

@app.route('/', methods=["GET", "POST"])
def index():
    if request.method == "POST":
        link = request.form.get('Link')
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            info_dict = ydl.extract_info(link, download=False)
            video_url = info_dict.get("url", None)
            video_id = info_dict.get("id", None)
            video_title = info_dict.get('title', None)
            ydl.download([link])
        print("sending file...")
        send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
        print("file sent, deleting...")
        os.remove("dl/"+video_title+".f137.mp4")
        print("done.")
        return render_template("index.html", message="Success!")
    else:
        return render_template("index.html", message=message)

我添加 .f137.mp4 的唯一原因是因为我使用 AWS C9 作为我的在线 IDE,我无法安装 FFMPEG 以在 Amazon Linux 上组合音频和视频。然而,这不是问题。问题是它没有发送下载请求。

这是控制台输出:

127.0.0.1 - - [12/Dec/2018 16:17:41] "POST / HTTP/1.1" 200 -
[youtube] 2AYgi2wsdkE: Downloading webpage
[youtube] 2AYgi2wsdkE: Downloading video info webpage
[youtube] 2AYgi2wsdkE: Downloading webpage
[youtube] 2AYgi2wsdkE: Downloading video info webpage
WARNING: You have requested multiple formats but ffmpeg or avconv are not installed. The formats won't be merged.
[download] Destination: dl/Meme Awards v244.f137.mp4
[download] 100% of 73.82MiB in 00:02
[download] Destination: dl/Meme Awards v244.f140.m4a
[download] 100% of 11.63MiB in 00:00
sending file...
file sent, deleting...
done.
127.0.0.1 - - [12/Dec/2018 16:18:03] "POST / HTTP/1.1" 200 -

我们不胜感激。谢谢!

【问题讨论】:

    标签: python flask ffmpeg youtube-dl


    【解决方案1】:

    你需要returnsend_file的结果:

    @app.route('/', methods=["GET", "POST"])
    def index():
        if request.method == "POST":
            link = request.form.get('Link')
            with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                info_dict = ydl.extract_info(link, download=False)
                video_url = info_dict.get("url", None)
                video_id = info_dict.get("id", None)
                video_title = info_dict.get('title', None)
                ydl.download([link])
            print("sending file...")
            return send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
        else:
            return render_template("index.html", message=message)
    

    不幸的是,这将使您在发送文件后更难“清理”,因此您可能希望将其作为计划维护的一部分(例如,运行 cron 作业以删除旧下载的文件)。有关该问题的更多信息,请参阅here

    【讨论】:

      【解决方案2】:

      正如罗布·布里切诺所说,

      需要返回send_file的结果

      所以你可以保存“flask.send_file”的结果,然后清理,然后返回结果。

      print("sending file...")
      result = send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
      print("file sent, deleting...")
      os.remove("dl/"+video_title+".f137.mp4")
      return result
      

      【讨论】:

      • 如果可行的话,那就更好了!但是send_file() 不是异步运行的吗?你怎么能确定os.remove()send_file() 在这里完成之后运行?
      【解决方案3】:

      扩展@Rob Bricheno的回答,如果需要在请求后清理,可以创建一个延迟方法,在请求完成后执行:

      @app.route('/', methods=["GET", "POST"])
      def index():
          if request.method == "POST":
              link = request.form.get('Link')
              with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                  info_dict = ydl.extract_info(link, download=False)
                  video_url = info_dict.get("url", None)
                  video_id = info_dict.get("id", None)
                  video_title = info_dict.get('title', None)
                  ydl.download([link])
              print("sending file...")
              response = send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
              # Create handle for processing display results (non-blocking, excecutes after response is returned)
              @flask.after_this_request
              def add_close_action(response):
                  @response.call_on_close
                  def process_after_request():
                      try:
                          print("file sent, deleting...")
                          os.remove("dl/"+video_title+".f137.mp4")
                          print("done.")
                      except Exception as e:
                          logger.exception(str(e))
              return response
          else:
              return render_template("index.html", message=message)
      

      【讨论】:

      • 这太酷了!但显然它只能在 Linux 上工作(如果仍然有一个打开的文件指针,即使在删除后也可以读取文件)。我在这里stackoverflow.com/questions/24612366/… 发现了一些关于这个和其他技术的更有趣的讨论
      • @Rob Bricheno Mine 与链接不同。这也可能解决他的问题。 after_this_request 在请求之后但在响应发送之前运行(本质上是修改响应的最后机会)。额外的 response.call_on_close 将其推迟到发送响应之后。所以它应该可以在linux和windows上运行。
      • 如果即使在发送响应后文件仍然存在的问题,您需要执行临时文件解决方法。但我的猜测是 send_file 是响应本身的一部分。
      猜你喜欢
      • 2021-08-19
      • 1970-01-01
      • 2016-01-08
      • 2015-10-11
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2014-12-09
      • 2021-12-24
      相关资源
      最近更新 更多