1+ from pathlib import Path
2+
13from fastapi import FastAPI , Request
24from fastapi .responses import HTMLResponse , JSONResponse
35from starlette .exceptions import HTTPException as StarletteHTTPException
46
57from app .core .templates import render_template
68
9+ FRONTEND_INDEX = Path (__file__ ).resolve ().parents [2 ] / "frontend" / "dist" / "index.html"
10+ SPA_REDIRECT_HTML = """<!doctype html>
11+ <html lang="en">
12+ <head>
13+ <meta charset="utf-8" />
14+ <title>Redirecting…</title>
15+ <meta http-equiv="refresh" content="0; url=/app/404" />
16+ <script>
17+ window.location.replace("/app/404");
18+ </script>
19+ </head>
20+ <body style="font-family: sans-serif; background: #05070f; color: #f8fafc; text-align: center; padding: 3rem;">
21+ <p>Routing you to the AlterBase CDN app…</p>
22+ <noscript>
23+ JavaScript is required for the dashboard. <a href="/app/404">Continue to the Not Found page</a>.
24+ </noscript>
25+ </body>
26+ </html>
27+ """
28+
729
830def register_exception_handlers (app : FastAPI ) -> None :
931 @app .exception_handler (404 )
@@ -12,6 +34,9 @@ async def not_found_handler(request: Request, exc: StarletteHTTPException):
1234 detail = exc .detail if hasattr (exc , "detail" ) else "Not Found"
1335 if "application/json" in accept and "text/html" not in accept :
1436 return JSONResponse ({"detail" : detail }, status_code = 404 )
37+ if FRONTEND_INDEX .exists () and ("text/html" in accept or "application/json" not in accept ):
38+ # Surface the React SPA's NotFound route while keeping a 404 status code
39+ return HTMLResponse (content = SPA_REDIRECT_HTML , status_code = 404 )
1540 detail_text = (
1641 detail
1742 if detail not in (None , "" , "Not found" , "Not Found" )
0 commit comments