flask.Response 无法在 Web 浏览器中开始下载

Download doesn't start in web browser by flask.Response

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

@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']})

在模板中,我们有一个 link 作为 <a href="/download/adkdsk457jds/240p/mp4/">Download 240p Video</a>,当它被点击时,它应该开始下载该视频。

问题是:

它在某些没有安装下载管理器(如 IDM 等)的浏览器中工作正常。但是 IDM 无法下载它。 IDM 只是挂在 http://example.com/download/adkdsk457jds/240p/mp4/

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

但是,在未安装 IDM 或其他下载管理器的情况下,Chrome 可以成功下载视频。

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

'Content-Type': 'application/octet-stream' 添加到 headers

您没有包含任何响应信息,包括内容类型;您需要复制有关原始响应的更多信息,以传达您返回的响应类型。否则使用默认值(由 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 底层原始文件 object;这也应该有效,但还有一个额外的好处,即保留 YouTube 应用的任何压缩。

一些下载管理器可能会尝试使用 HTTP range request 来并行下载,即使服务器没有通告它支持此类请求。您可能应该使用 406 Not Acceptable 响应进行响应(在不支持的情况下请求字节范围是 Accept-* 违规行为)。您需要记录下载管理器发送的内容 headers 以确定是否属于这种情况。