【问题标题】:Download doesn't start in web browser by flask.Responseflask.Response 无法在 Web 浏览器中开始下载
【发布时间】:2015-03-24 17:02:41
【问题描述】:

在 Flask(微型 Web 框架)中,我们有一个视图:

@app.route('/download/<id>/<resolution>/<extension>/')
def download_by_id(id, resolution=None, extension=None):
    stream = youtube.stream_url(id, resolution, extension)
    binary = requests.get(stream['url'], stream=True)
    return flask.Response(
        binary,
        headers={'Content-Disposition': 'attachment; '
                                        'filename=' + stream['filename']})

在模板中,我们有一个链接为&lt;a href="/download/adkdsk457jds/240p/mp4/"&gt;Download 240p Video&lt;/a&gt;,当点击它时,它应该开始下载该视频。

问题是:

在一些没有安装 IDM 等下载管理器的浏览器中运行良好。但是 IDM 无法下载它。 IDM 只是挂在http://example.com/download/adkdsk457jds/240p/mp4/

Firefox 自己的下载管理器也是如此。 Firefox 只是下载一个普通的 .html 页面,而不是实际的视频。

但是,当没有安装 IDM 或其他下载管理器时,视频会在 Chrome 中成功下载。

请帮助和建议为什么它不起作用。我需要更改代码中的某些内容吗?

【问题讨论】:

  • 您是否尝试更改网址以使其以.mp4 结尾?
  • 通过url,你的意思是把文件名改成video1.mp4还是什么?
  • 你的 route 参数和 href 包含什么。
  • @BartoszMarcinkowski 好吧,我不确定您所说的 href 是什么意思,但这里 href 指的是我上面展示的烧瓶视图。所以不确定在这里添加扩展会有什么帮助?
  • 下载管理器希望能够使用 HTTP-Range 请求; Flask 未设置为执行范围。我怀疑这就是造成这里问题的原因。

标签: python file stream flask python-requests


【解决方案1】:

在标题中添加'Content-Type': 'application/octet-stream'

【讨论】:

  • 我只是给了你一个提示,因为你提到“Firefox 只是下载一个普通的 .html 页面”。而且我认为 http-range 应该始终与 content-type 结合使用。
  • 嗯,对我来说它就像魅力一样。 :-) 只需将其添加到标题中,下载管理器就可以正确捕获文件。但是下载管理器的time leftfile size还是不见了,需要做什么?
  • 不,HTTP Range 适用于任何 mimetype。例如,Acrobat Reader 广泛使用它来提前加载特定页面。当您跳过已经缓冲的视频部分时,视频播放器会使用它。下载管理器使用它来并行下载视频中的不同部分。
  • 但是当您在 YouTube 的响应中有 正确 内容类型时,盲目地将内容类型设置为 application/octet-stream 是错误的做法?
  • 通常让它可下载是正确的做法。
【解决方案2】:

您没有包含任何响应信息,包括内容类型;您需要复制有关原始响应的更多信息,以传达您返回的响应类型。否则使用默认值(由 HTTP 标准或 Flask 规定)。

具体来说,您至少要跨内容类型、长度和传输编码进行复制:

headers={
    'Content-Disposition': 'attachment; filename=' + stream['filename']
}
for header in ('content-type', 'content-length', 'transfer-encoding'):
    if header in binary.headers:
        headers[header] = binary.headers[header]
return flask.Response(binary.raw, headers=headers)

我正在使用response.raw 底层原始文件对象;这也应该有效,但还有一个额外的好处是保留了 YouTube 应用的任何压缩。

一些下载管理器可能会尝试使用HTTP range request 来获取并行下载,即使服务器并未宣传它支持此类请求。您可能应该用 406 Not Acceptable 响应(在不受支持时请求字节范围是 Accept-* 违规)。您需要记录下载管理器发送的标头以确定是否是这种情况。

【讨论】:

  • 你指的是什么response
  • @CracLock:抱歉,您在代码中将其命名为 binary
  • 有没有办法确定file sizetime的运行,使用这个binary?这样它就可以通过headers 发送给下载管理员。
  • @CracLock: content-length 是文件大小;不知道你所说的 time 是什么意思;还有一个 date 标头你也可以复制。
  • 好吧,它不适用于流的content-type,假设video/3gpp(它只是挂起并且永远不会在下载管理器中开始下载)但如果我将它专门设置为application/octet-stream一切工作正常。有没有办法解决它?与flask.Response 有什么关系?
猜你喜欢
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
相关资源
最近更新 更多