我有一个 Flask 应用程序,它将提供一个端点来下载一个大文件。但是,不是从文件系统提供它或即时生成文件,而是必须首先通过 HTTP 从另一台服务器下载该文件。
当然,我可以先向外部服务器执行 GET 请求,完整下载文件并将其存储在文件系统或内存中,然后作为第二步提供原始请求的结果。这看起来像这样(还包括一个基本的身份验证,以表明为什么在较低层上的简单代理是不够的):
#!flask/bin/python
from flask import Flask, jsonify
import os
import requests
from requests.auth import HTTPBasicAuth
app = Flask(__name__)
@app.route('/download')
def download():
auth = HTTPBasicAuth("some_user", "some_password")
session = requests.Session()
session.auth = auth
response = session.get("http://example.com")
return response.content
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1234, debug=True)
Run Code Online (Sandbox Code Playgroud)
但是,这会增加应用程序的延迟和存储要求。而且,即使接收方只需要执行文件的部分下载(即执行 HTTP 范围请求),也必须首先从外部服务器完全获取文件。
有没有更优雅的选择来解决这个问题,即为直接转发到外部服务器的 HTTP 范围请求提供支持?
根据Proxying to another web service with Flask,Download large file in python with requests和Flask large file download我设法在流模式下制作了一个 Flask HTTP 代理。
from flask import Flask, request, Response
import requests
PROXY_URL = 'http://ipv4.download.thinkbroadband.com/'
def download_file(streamable):
with streamable as stream:
stream.raise_for_status()
for chunk in stream.iter_content(chunk_size=8192):
yield chunk
def _proxy(*args, **kwargs):
resp = requests.request(
method=request.method,
url=request.url.replace(request.host_url, PROXY_URL),
headers={key: value for (key, value) in request.headers if key != 'Host'},
data=request.get_data(),
cookies=request.cookies,
allow_redirects=False,
stream=True)
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
headers = [(name, value) for (name, value) in resp.raw.headers.items()
if name.lower() not in excluded_headers]
return Response(download_file(resp), resp.status_code, headers)
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def download(path):
return _proxy()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1234, debug=True)
Run Code Online (Sandbox Code Playgroud)
download_file() 将以流模式打开请求,并在流传输后立即生成每个块。
_proxy()创建请求,然后Response使用迭代器download_file()作为内容创建并返回一个 Flask 。
我使用https://www.thinkbroadband.com/download对其进行了测试,其中有几个存档文件可以免费下载以进行测试。(小心,档案已损坏,因此您最好使用校验和来确保您获得了预期的文件)。
一些例子:
curl 'http://0.0.0.0:1234/100MB.zip' --output /tmp/100MB.zip
curl 'http://0.0.0.0:1234/20MB.zip' --output /tmp/20MB.zip
Run Code Online (Sandbox Code Playgroud)
我还在随机网站上进行了一些其他测试以获得大图像。到目前为止,我没有遇到任何问题。
| 归档时间: |
|
| 查看次数: |
1671 次 |
| 最近记录: |