perf(B04): 응답 압축 + 좌표 자릿수 정리로 내려보낼 양 축소
DB·파일에는 뜻 없는 자릿수가 붙어 있고(1.4000000000000001 꼴) 서버는 응답을 전혀 압축하지 않고 있었음. B05 한 번 진입에 118MB 수신(2026-09-06 실측). - main.py: 압축 미들웨어(1KB 이상). 3D 예상형상(/corridor)은 예외 — 숫자 배열이라 절반만 줄면서 압축에 493ms 듦(18.6->9.4MB). - common_util_json: round_floats(value, digits) + LONLAT_DIGITS 7(1.1cm) · METRE_DIGITS 6. 저장 파일은 그대로 두고 내려보낼 때만 줄임. 브라우저가 다시 계산에 넣는 값(종횡단 지반선)은 줄이면 안 된다고 머리에 경고 적음. - 도엽 GeoJSON: 자릿수만 줄인 표시용 사본(.display.geojson)을 한 번 만들어 서빙. 원본이 새로 깔리면 자동 재생성, 실패하면 원본 그대로. 등고선 도엽 65.9->36.8MB, 압축까지 11.3MB. - 배수유역 응답: 위경도 7자리. 151->100KB, 압축 22KB. ruff 통과, 테스트 390 통과·17 건너뜀. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,9 +17,11 @@ import signal
|
||||
import subprocess
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from A06_Login.A06_Login_Router import router as a06_login_router
|
||||
@@ -329,6 +331,35 @@ app.add_middleware(
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# 응답 압축 (2026-09-06 실측으로 도입)
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# 화면 한 번 여는 데 수십 MB 가 오간다 — 종횡단 상세 1.56MB → 0.34MB(압축 13ms),
|
||||
# 배수유역 151KB → 37KB, 지형 도엽 GeoJSON 은 훨씬 크다. 사무실 랜에서는 티가 덜 나지만
|
||||
# 현장에서 인터넷으로 열면 이 차이가 곧 대기 시간이다.
|
||||
#
|
||||
# 딱 하나 예외 — 3D 예상형상(코리도)은 숫자 배열이라 절반밖에 안 줄면서 압축에만 493ms 가
|
||||
# 든다(18.6MB → 9.4MB). 그 자리는 「덜 보내기」가 아니라 「안 보내기」로 푼다.
|
||||
_COMPRESS_MIN_BYTES = 1024
|
||||
|
||||
|
||||
def _skips_compression(path: str) -> bool:
|
||||
"""압축에서 뺄 경로인가 — 지금은 코리도 하나뿐."""
|
||||
return path.endswith("/corridor")
|
||||
|
||||
|
||||
class _SelectiveGZipMiddleware(GZipMiddleware):
|
||||
"""경로 몇 개만 빼고 압축한다. 나머지 동작은 표준 미들웨어 그대로."""
|
||||
|
||||
async def __call__(self, scope: Any, receive: Any, send: Any) -> None:
|
||||
if scope["type"] == "http" and _skips_compression(scope.get("path", "")):
|
||||
await self.app(scope, receive, send)
|
||||
return
|
||||
await super().__call__(scope, receive, send)
|
||||
|
||||
|
||||
app.add_middleware(_SelectiveGZipMiddleware, minimum_size=_COMPRESS_MIN_BYTES)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# 정적 파일 서빙 (프론트엔드)
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user