1- from fastapi import FastAPI , WebSocket , WebSocketDisconnect
1+ from fastapi import FastAPI , WebSocket , WebSocketDisconnect , Request
22from fastapi .staticfiles import StaticFiles
3+ from fastapi .responses import FileResponse , JSONResponse
4+ from starlette .exceptions import HTTPException as StarletteHTTPException
35from loguru import logger
46
57from server .core .protocol import process_binary_command
@@ -26,6 +28,17 @@ async def websocket_endpoint(websocket: WebSocket):
2628 except Exception as e :
2729 logger .error (f"WebSocket error: { e } " )
2830
31+ # SPA Fallback for 404 errors
32+ @app .exception_handler (404 )
33+ async def not_found_handler (request : Request , exc : StarletteHTTPException ):
34+ index_path = static_dir / "index.html"
35+ if index_path .exists ():
36+ logger .debug (f"404 for { request .url .path } , falling back to index.html" )
37+ return FileResponse (index_path )
38+
39+ logger .warning (f"404 for { request .url .path } and index.html not found in { static_dir } " )
40+ return JSONResponse ({"detail" : "Not Found" }, status_code = 404 )
41+
2942 # 挂载静态文件(必须放在最后,否则可能覆盖 API 路由)
3043 if static_dir .exists ():
3144 app .mount ("/" , StaticFiles (directory = str (static_dir ), html = True ), name = "static" )
0 commit comments