fix: Add HEAD method support to assets proxy endpoint
- Add HEAD method handler for browser preflight requests - Use stat_object for HEAD requests (more efficient) - Return proper headers for HEAD requests - This fixes 405 errors when browser checks image availability
This commit is contained in:
@@ -325,7 +325,8 @@ async def update_agent_visibility_endpoint(
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
@router.get("/assets/proxy/{path:path}")
|
@router.get("/assets/proxy/{path:path}")
|
||||||
async def proxy_asset(path: str):
|
@router.head("/assets/proxy/{path:path}")
|
||||||
|
async def proxy_asset(path: str, request: Request):
|
||||||
"""
|
"""
|
||||||
Proxy endpoint for serving MinIO assets.
|
Proxy endpoint for serving MinIO assets.
|
||||||
|
|
||||||
@@ -352,15 +353,12 @@ async def proxy_asset(path: str):
|
|||||||
try:
|
try:
|
||||||
client = get_minio_client()
|
client = get_minio_client()
|
||||||
|
|
||||||
# Get object from MinIO
|
# Check if object exists and get metadata
|
||||||
# path already contains the full object key (e.g., "microdao/logo/2025/12/02/abc123.png")
|
try:
|
||||||
# ASSETS_BUCKET is prepended by get_object()
|
stat = client.stat_object(ASSETS_BUCKET, path)
|
||||||
response = client.get_object(ASSETS_BUCKET, path)
|
except Exception as e:
|
||||||
|
logger.warning(f"Asset not found in MinIO: {path}, error: {e}")
|
||||||
# Read data
|
raise HTTPException(status_code=404, detail="Asset not found")
|
||||||
data = response.read()
|
|
||||||
response.close()
|
|
||||||
response.release_conn()
|
|
||||||
|
|
||||||
# Determine content type
|
# Determine content type
|
||||||
content_type = "application/octet-stream"
|
content_type = "application/octet-stream"
|
||||||
@@ -373,14 +371,36 @@ async def proxy_asset(path: str):
|
|||||||
elif path.endswith('.gif'):
|
elif path.endswith('.gif'):
|
||||||
content_type = 'image/gif'
|
content_type = 'image/gif'
|
||||||
|
|
||||||
return StreamingResponse(
|
# For HEAD requests, return headers only
|
||||||
io.BytesIO(data),
|
if request.method == 'HEAD':
|
||||||
media_type=content_type,
|
from fastapi.responses import Response
|
||||||
|
return Response(
|
||||||
|
status_code=200,
|
||||||
headers={
|
headers={
|
||||||
|
'Content-Type': content_type,
|
||||||
|
'Content-Length': str(stat.size),
|
||||||
'Cache-Control': 'public, max-age=86400, immutable',
|
'Cache-Control': 'public, max-age=86400, immutable',
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# For GET requests, return file data
|
||||||
|
response = client.get_object(ASSETS_BUCKET, path)
|
||||||
|
data = response.read()
|
||||||
|
response.close()
|
||||||
|
response.release_conn()
|
||||||
|
|
||||||
|
return StreamingResponse(
|
||||||
|
io.BytesIO(data),
|
||||||
|
media_type=content_type,
|
||||||
|
headers={
|
||||||
|
'Content-Length': str(stat.size),
|
||||||
|
'Cache-Control': 'public, max-age=86400, immutable',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to proxy asset {path}: {e}")
|
logger.error(f"Failed to proxy asset {path}: {e}")
|
||||||
raise HTTPException(status_code=404, detail="Asset not found")
|
raise HTTPException(status_code=404, detail="Asset not found")
|
||||||
|
|||||||
Reference in New Issue
Block a user