fix(dashboard): return 404 JSON for unmatched /api paths instead of SPA HTML
The SPA catch-all (serve_spa) served index.html for any unmatched GET,
including unregistered /api/* endpoints. A missing API route therefore
came back as <!doctype html> with status 200, and JSON clients (the
desktop app's fetchJson) crashed with an opaque
'SyntaxError: Unexpected token <' instead of a clear error.
- web_server.py: unmatched /api or /api/... now returns 404 JSON
('No such API endpoint'); non-api paths still serve the SPA for
client-side routing.
- main.cjs fetchJson: detect an HTML body / text/html content-type on a
2xx response and reject with a clear message naming the URL, rather
than a raw JSON.parse SyntaxError. Empty bodies resolve to null;
malformed JSON reports the URL plus a snippet.
This commit is contained in:
@@ -4758,6 +4758,17 @@ def mount_spa(application: FastAPI):
|
||||
@application.get("/{full_path:path}")
|
||||
async def serve_spa(full_path: str, request: Request):
|
||||
prefix = _normalise_prefix(request.headers.get("x-forwarded-prefix"))
|
||||
# An unmatched /api/* path is a missing/renamed endpoint, NOT a
|
||||
# client-side route. Falling through to index.html here returns
|
||||
# `<!doctype html>` with status 200, which makes JSON clients (the
|
||||
# desktop app's fetchJson, dashboard fetch wrappers) blow up with an
|
||||
# opaque `SyntaxError: Unexpected token '<'`. Return a real 404 JSON
|
||||
# so the caller sees a clear "no such endpoint" instead.
|
||||
if full_path == "api" or full_path.startswith("api/"):
|
||||
return JSONResponse(
|
||||
{"detail": f"No such API endpoint: /{full_path}"},
|
||||
status_code=404,
|
||||
)
|
||||
file_path = WEB_DIST / full_path
|
||||
# Prevent path traversal via url-encoded sequences (%2e%2e/)
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user