```
feat(api): 添加 MinIO 文件下载支持并优化流处理 添加了对 MinIO 存储文件的直接下载支持,包括: - 新增 urlparse 和 Config 导入用于 URL 解析和配置读取 - 集成 s3_client 扩展用于 MinIO 对象存储操作 - 实现同源文件检测逻辑,判断是否为 MinIO 存储的文件 - 添加 MinIO 文件流式下载功能,支持大文件处理 - 优化流处理过程中的资源管理,确保请求和文件对象正确关闭 - 增强安全性,验证同源策略防止任意 URL 访问 ```
This commit is contained in:
parent
bdbec1a310
commit
4ece904c25
@ -1,5 +1,7 @@
|
||||
from flask import Blueprint, request, jsonify, session, current_app
|
||||
from extensions import db, redis_client
|
||||
from urllib.parse import unquote, urlparse
|
||||
from config import Config
|
||||
from extensions import db, redis_client, s3_client
|
||||
from models import User, SavedPrompt
|
||||
from middlewares.auth import login_required
|
||||
from services.logger import system_logger
|
||||
@ -244,12 +246,39 @@ def download_proxy():
|
||||
return jsonify({"error": "缺少 URL 参数"}), 400
|
||||
|
||||
try:
|
||||
parsed_url = urlparse(url)
|
||||
public_prefix = Config.MINIO["public_url"].rstrip("/") + "/"
|
||||
is_same_origin_file = (
|
||||
parsed_url.path.startswith(public_prefix)
|
||||
and (not parsed_url.scheme or parsed_url.netloc == request.host)
|
||||
)
|
||||
if is_same_origin_file:
|
||||
object_key = unquote(parsed_url.path[len(public_prefix):])
|
||||
file_obj = s3_client.get_object(Bucket=Config.MINIO["bucket"], Key=object_key)
|
||||
headers = {
|
||||
"Content-Type": file_obj.get("ContentType") or "application/octet-stream",
|
||||
"Content-Disposition": f'attachment; filename="{filename}"',
|
||||
"Cache-Control": "private, max-age=0",
|
||||
}
|
||||
|
||||
def generate_minio_stream():
|
||||
try:
|
||||
for chunk in file_obj["Body"].iter_chunks(chunk_size=4096):
|
||||
yield chunk
|
||||
finally:
|
||||
file_obj["Body"].close()
|
||||
|
||||
return current_app.response_class(generate_minio_stream(), headers=headers)
|
||||
|
||||
req, headers = get_remote_file_stream(url)
|
||||
headers["Content-Disposition"] = f'attachment; filename="{filename}"'
|
||||
|
||||
def generate_stream():
|
||||
try:
|
||||
for chunk in req.iter_content(chunk_size=4096):
|
||||
yield chunk
|
||||
finally:
|
||||
req.close()
|
||||
|
||||
return current_app.response_class(generate_stream(), headers=headers)
|
||||
except Exception as e:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user