diff --git a/backend/common/core/response_middleware.py b/backend/common/core/response_middleware.py index 922035fa..91aa6178 100644 --- a/backend/common/core/response_middleware.py +++ b/backend/common/core/response_middleware.py @@ -30,9 +30,9 @@ async def dispatch(self, request, call_next): direct_paths = [ f"{settings.API_V1_STR}/mcp/mcp_question", f"{settings.API_V1_STR}/mcp/mcp_assistant", - "/openapi.json", - "/docs", - "/redoc" + f"{settings.CONTEXT_PATH}/openapi.json", + f"{settings.CONTEXT_PATH}/docs", + f"{settings.CONTEXT_PATH}/redoc" ] route = request.scope.get("route") @@ -40,7 +40,7 @@ async def dispatch(self, request, call_next): path_pattern = '' if not route else route.path_format if (isinstance(response, JSONResponse) - or request.url.path == f"{settings.API_V1_STR}/openapi.json" + or request.url.path == f"{settings.CONTEXT_PATH}/openapi.json" or path_pattern in direct_paths): return response if response.status_code != 200: diff --git a/backend/main.py b/backend/main.py index 689fff66..3a72bb06 100644 --- a/backend/main.py +++ b/backend/main.py @@ -70,7 +70,7 @@ def custom_generate_unique_id(route: APIRoute) -> str: app = FastAPI( title=settings.PROJECT_NAME, - openapi_url=f"{settings.API_V1_STR}/openapi.json", + openapi_url=f"{settings.CONTEXT_PATH}/openapi.json", generate_unique_id_function=custom_generate_unique_id, lifespan=lifespan, docs_url=None, @@ -152,23 +152,23 @@ def generate_openapi_for_lang(lang: str) -> Dict[str, Any]: # custom /openapi.json and /docs -@app.get("/openapi.json", include_in_schema=False) +@app.get(f"{settings.CONTEXT_PATH}/openapi.json", include_in_schema=False) async def custom_openapi(request: Request): lang = get_language_from_request(request) schema = generate_openapi_for_lang(lang) return JSONResponse(schema) -@app.get("/docs", include_in_schema=False) +@app.get(f"{settings.CONTEXT_PATH}/docs", include_in_schema=False) async def custom_swagger_ui(request: Request): lang = get_language_from_request(request) from fastapi.openapi.docs import get_swagger_ui_html return get_swagger_ui_html( - openapi_url=f"/openapi.json?lang={lang}", + openapi_url=f"./openapi.json?lang={lang}", title="SQLBot API Docs", swagger_favicon_url="https://fastapi.tiangolo.com/img/favicon.png", - swagger_js_url="/swagger-ui-bundle.js", - swagger_css_url="/swagger-ui.css", + swagger_js_url="./swagger-ui-bundle.js", + swagger_css_url="./swagger-ui.css", ) diff --git a/frontend/public/swagger-ui-bundle.js b/frontend/public/swagger-ui-bundle.js index cdbe29ac..dcfadae0 100644 --- a/frontend/public/swagger-ui-bundle.js +++ b/frontend/public/swagger-ui-bundle.js @@ -41749,7 +41749,8 @@ const s = new Error(a.statusText || `response status is ${a.status}`) // if (a.status === 401 && a.statusText === 'Unauthorized') { if (a.status === 401) { - location.href = location.pathname.replace('/docs', '/') + '#/401?title=unauthorized&target=docs' + location.href = + location.pathname.replace('/docs', '/') + '#/401?title=unauthorized&target=docs' return a } throw ((s.status = a.status), (s.statusCode = a.status), (s.response = a), s) @@ -56482,8 +56483,15 @@ const a = o.getConfigs().withCredentials o.fn.fetch.withCredentials = a }) + function getTokenKey() { + var pathname = window.location.pathname.replace('docs', '') + var match = pathname.match(/^\/([^\/]+)/) + var prefix = match ? `${match[1]}_` : 'sqlbot_v1_' + return `${prefix}user.token` + } function get_token() { - var tokenCache = localStorage.getItem('user.token') + var token_key = getTokenKey() + var tokenCache = localStorage.getItem(token_key) if (!tokenCache) { return null } diff --git a/frontend/src/components/layout/Apikey.vue b/frontend/src/components/layout/Apikey.vue index d55e37a1..ee17bd56 100644 --- a/frontend/src/components/layout/Apikey.vue +++ b/frontend/src/components/layout/Apikey.vue @@ -38,7 +38,7 @@ const handleAdd = () => { const pwd = ref('**********') const toApiDoc = () => { console.log('Add API Key') - const url = '/docs' + const url = './docs' window.open(url, '_blank') } diff --git a/frontend/src/utils/useCache.ts b/frontend/src/utils/useCache.ts index c7cda2af..256da214 100644 --- a/frontend/src/utils/useCache.ts +++ b/frontend/src/utils/useCache.ts @@ -1,13 +1,50 @@ import WebStorageCache from 'web-storage-cache' -type CacheType = 'sessionStorage' | 'localStorage' +type CacheType = 'localStorage' | 'sessionStorage' + +const getPathPrefix = () => { + const pathname = window.location.pathname + // eslint-disable-next-line no-useless-escape + const match = pathname.match(/^\/([^\/]+)/) + return match ? `${match[1]}_` : 'sqlbot_v1_' +} export const useCache = (type: CacheType = 'localStorage') => { - const wsCache: WebStorageCache = new WebStorageCache({ - storage: type, + const originalCache = new WebStorageCache({ storage: type }) + const prefix = getPathPrefix() + + const methodsNeedKeyPrefix = new Set(['get', 'delete', 'touch', 'add', 'replace']) + + const wrappedCache = new Proxy(originalCache, { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + get(target, prop, _receiver) { + const originalMethod = target[prop as keyof typeof target] + + if (typeof originalMethod !== 'function') { + return originalMethod + } + + if (methodsNeedKeyPrefix.has(prop as string)) { + return function (this: any, key: string, ...args: any[]) { + // 自动加上前缀 + const scopedKey = `${prefix}${key}` + return (originalMethod as (...args: any[]) => any).apply(target, [scopedKey, ...args]) + } + } + + if (prop === 'set') { + return function (this: any, key: string, value: any, ...args: any[]) { + const scopedKey = `${prefix}${key}` + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + return (originalMethod as Function).apply(target, [scopedKey, value, ...args]) + } + } + + return originalMethod.bind(target) + }, }) return { - wsCache, + wsCache: wrappedCache, } }