From 0e4d5708e41eb37729b7d712225c617e38a454c5 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:25:39 +1000 Subject: [PATCH] fix(api): UI crash with `TypeError: i.map is not a function` This pops up every now and then and I could never figure it out. A user figured it out in #6936. The cause is appending a query string to the app URL. For example: ```sh http://127.0.0.1:9090/?__theme=dark ``` The query string breaking the static file serving, which prevents our translations from loading correctly. Instead of the JSON translations, FastAPI sends the index HTML page. The UI then errors when attempting to parse the translation JSON. The query string ?__theme=dark is used by Gradio to force dark mode. I believe the users with this issue are doing the same thing the user in #6936 did (just change the port number on an existing bookmark) or their browser history/bookmark includes the query string. Though this is technically a user-caused problem (we cannot prevent the user from using a malformed URL), we can work around it. When query string is used on the root path, we can redirect the browser to the root path without the query string. This is done via very simple middleware. Closes #6696 Closes #6817 Closes #6828 Closes #6936 Closes #6983 --- invokeai/app/api_app.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index ce619642462..bab5121b285 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -7,13 +7,14 @@ import torch import uvicorn -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html -from fastapi.responses import HTMLResponse +from fastapi.responses import HTMLResponse, RedirectResponse from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from torch.backends.mps import is_available as is_mps_available # for PyCharm: @@ -78,6 +79,29 @@ async def lifespan(app: FastAPI): lifespan=lifespan, ) + +class RedirectRootWithQueryStringMiddleware(BaseHTTPMiddleware): + """When a request is made to the root path with a query string, redirect to the root path without the query string. + + For example, to force a Gradio app to use dark mode, users may append `?__theme=dark` to the URL. Their browser may + have this query string saved in history or a bookmark, so when the user navigates to `http://127.0.0.1:9090/`, the + browser takes them to `http://127.0.0.1:9090/?__theme=dark`. + + This breaks the static file serving in the UI, so we redirect the user to the root path without the query string. + """ + + async def dispatch(self, request: Request, call_next: RequestResponseEndpoint): + if request.url.path == "/" and request.url.query: + return RedirectResponse(url="/") + + response = await call_next(request) + return response + + +# Add the middleware +app.add_middleware(RedirectRootWithQueryStringMiddleware) + + # Add event handler event_handler_id: int = id(app) app.add_middleware(