mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
fix: agentbox using nginx for traffic proxy
This commit is contained in:
@ -744,9 +744,10 @@ CLI_API_URL=http://localhost:5001
|
||||
# Base URL for storage file ticket API endpoints (upload/download).
|
||||
# Used by sandbox containers (internal or external like e2b) that need an absolute,
|
||||
# routable address to reach the Dify API file endpoints.
|
||||
# Falls back to FILES_URL if not specified.
|
||||
# Required for sandbox runtime file access.
|
||||
# For local development: http://localhost:5001
|
||||
# For Docker deployment: http://api:5001
|
||||
# For all-in-one Docker deployment with nginx: http://localhost
|
||||
# For public/remote sandbox environments (e.g., e2b): use a public domain or IP
|
||||
FILES_API_URL=http://localhost:5001
|
||||
|
||||
# Optional defaults for SSH sandbox provider setup (for manual config/CLI usage).
|
||||
|
||||
@ -377,8 +377,8 @@ class FileAccessConfig(BaseSettings):
|
||||
description="Base URL for storage file ticket API endpoints."
|
||||
" Used by sandbox containers (internal or external like e2b) that need"
|
||||
" an absolute, routable address to upload/download files via the API."
|
||||
" Falls back to FILES_URL if not specified."
|
||||
" For Docker deployments, set to http://api:5001.",
|
||||
" For all-in-one Docker deployments, set to http://localhost."
|
||||
" For public sandbox environments, set to a public domain or IP.",
|
||||
default="",
|
||||
)
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ Usage:
|
||||
url = StorageTicketService.create_upload_url("path/to/file.txt", expires_in=300, max_bytes=10*1024*1024)
|
||||
|
||||
URL format:
|
||||
{FILES_API_URL}/files/storage-files/{token} (falls back to FILES_URL)
|
||||
{FILES_API_URL}/files/storage-files/{token}
|
||||
|
||||
The token is validated by looking up the Redis key, which contains:
|
||||
- op: "download" or "upload"
|
||||
@ -137,6 +137,17 @@ class StorageTicketService:
|
||||
|
||||
@classmethod
|
||||
def _build_url(cls, token: str) -> str:
|
||||
"""Build the full URL for a token."""
|
||||
base_url = dify_config.FILES_API_URL
|
||||
"""Build the full URL for a token.
|
||||
|
||||
FILES_API_URL is dedicated to sandbox runtime file access (agentbox/e2b/etc.).
|
||||
This endpoint must be routable from the runtime environment.
|
||||
"""
|
||||
base_url = dify_config.FILES_API_URL.strip()
|
||||
if not base_url:
|
||||
raise ValueError(
|
||||
"FILES_API_URL is required for sandbox runtime file access. "
|
||||
"Set FILES_API_URL to a URL reachable by your sandbox runtime. "
|
||||
"For public sandbox environments (e.g. e2b), use a public domain or IP."
|
||||
)
|
||||
base_url = base_url.rstrip("/")
|
||||
return f"{base_url}/files/storage-files/{token}"
|
||||
|
||||
@ -156,6 +156,7 @@ def test_bundle_import_zip_storage_key():
|
||||
def test_storage_ticket_service(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Test StorageTicketService creates and retrieves tickets."""
|
||||
monkeypatch.setattr(dify_config, "FILES_URL", "http://files.local", raising=False)
|
||||
monkeypatch.setattr(dify_config, "FILES_API_URL", "http://files-api.local", raising=False)
|
||||
|
||||
mock_redis = MagicMock()
|
||||
stored_data = {}
|
||||
@ -172,7 +173,7 @@ def test_storage_ticket_service(monkeypatch: pytest.MonkeyPatch):
|
||||
with patch("services.storage_ticket_service.redis_client", mock_redis):
|
||||
url = StorageTicketService.create_download_url("test/path/file.txt", expires_in=300, filename="file.txt")
|
||||
|
||||
assert url.startswith("http://files.local/files/storage-files/")
|
||||
assert url.startswith("http://files-api.local/files/storage-files/")
|
||||
token = url.split("/")[-1]
|
||||
|
||||
ticket = StorageTicketService.get_ticket(token)
|
||||
@ -207,6 +208,7 @@ def test_ticket_url_generation(monkeypatch: pytest.MonkeyPatch):
|
||||
key = AssetPaths.draft(tenant_id, app_id, resource_id)
|
||||
|
||||
monkeypatch.setattr(dify_config, "FILES_URL", "http://files.local", raising=False)
|
||||
monkeypatch.setattr(dify_config, "FILES_API_URL", "http://files-api.local", raising=False)
|
||||
|
||||
mock_redis = MagicMock()
|
||||
mock_redis.setex = MagicMock()
|
||||
@ -222,7 +224,7 @@ def test_ticket_url_generation(monkeypatch: pytest.MonkeyPatch):
|
||||
)
|
||||
url = storage.get_download_url(key, expires_in=120)
|
||||
|
||||
assert url.startswith("http://files.local/files/storage-files/")
|
||||
assert url.startswith("http://files-api.local/files/storage-files/")
|
||||
token = url.split("/")[-1]
|
||||
assert len(token) == 36 # UUID format
|
||||
|
||||
@ -235,6 +237,7 @@ def test_upload_ticket_url_generation(monkeypatch: pytest.MonkeyPatch):
|
||||
key = AssetPaths.draft(tenant_id, app_id, resource_id)
|
||||
|
||||
monkeypatch.setattr(dify_config, "FILES_URL", "http://files.local", raising=False)
|
||||
monkeypatch.setattr(dify_config, "FILES_API_URL", "http://files-api.local", raising=False)
|
||||
|
||||
mock_redis = MagicMock()
|
||||
mock_redis.setex = MagicMock()
|
||||
@ -249,7 +252,7 @@ def test_upload_ticket_url_generation(monkeypatch: pytest.MonkeyPatch):
|
||||
)
|
||||
url = storage.get_upload_url(key, expires_in=120)
|
||||
|
||||
assert url.startswith("http://files.local/files/storage-files/")
|
||||
assert url.startswith("http://files-api.local/files/storage-files/")
|
||||
token = url.split("/")[-1]
|
||||
assert len(token) == 36 # UUID format
|
||||
|
||||
@ -289,3 +292,32 @@ def test_storage_ticket_pydantic():
|
||||
upload_json = upload_ticket.model_dump_json()
|
||||
restored_upload = StorageTicket.model_validate_json(upload_json)
|
||||
assert restored_upload.max_bytes == 1024
|
||||
|
||||
|
||||
def test_storage_ticket_uses_files_api_url_when_set(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Test that FILES_API_URL is used for runtime ticket URLs."""
|
||||
monkeypatch.setattr(dify_config, "FILES_URL", "http://files.local", raising=False)
|
||||
monkeypatch.setattr(dify_config, "FILES_API_URL", "https://runtime.example.com", raising=False)
|
||||
|
||||
mock_redis = MagicMock()
|
||||
mock_redis.setex = MagicMock()
|
||||
|
||||
with patch("services.storage_ticket_service.redis_client", mock_redis):
|
||||
url = StorageTicketService.create_download_url("test/path/file.txt", expires_in=300, filename="file.txt")
|
||||
|
||||
assert url.startswith("https://runtime.example.com/files/storage-files/")
|
||||
|
||||
|
||||
def test_storage_ticket_requires_files_api_url(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Test that ticket generation fails when FILES_API_URL is empty."""
|
||||
monkeypatch.setattr(dify_config, "FILES_URL", "http://files.local", raising=False)
|
||||
monkeypatch.setattr(dify_config, "FILES_API_URL", "", raising=False)
|
||||
|
||||
mock_redis = MagicMock()
|
||||
mock_redis.setex = MagicMock()
|
||||
|
||||
with (
|
||||
patch("services.storage_ticket_service.redis_client", mock_redis),
|
||||
pytest.raises(ValueError, match="FILES_API_URL is required"),
|
||||
):
|
||||
StorageTicketService.create_download_url("test/path/file.txt", expires_in=300, filename="file.txt")
|
||||
|
||||
Reference in New Issue
Block a user