perf: Optimize frontend localStorage key conflicts

This commit is contained in:
fit2cloud-chenyw
2026-04-14 12:04:13 +08:00
committed by fit2cloud-chenyw
parent 034191962f
commit 559c80c5b9
5 changed files with 62 additions and 17 deletions
+4 -4
View File
@@ -30,9 +30,9 @@ class ResponseMiddleware(BaseHTTPMiddleware):
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 @@ class ResponseMiddleware(BaseHTTPMiddleware):
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:
+6 -6
View File
@@ -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",
)
+10 -2
View File
@@ -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
}
+1 -1
View File
@@ -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')
}
+41 -4
View File
@@ -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,
}
}