From 5299d3d20a2fc02cb322ac7dc0e5e384d0454c3b Mon Sep 17 00:00:00 2001 From: shlab Date: Mon, 1 Jun 2026 18:01:42 +0800 Subject: [PATCH] feat(frontend): consume X-New-Token header for sliding token refresh The backend re-issues a token via the X-New-Token response header when the current one is near expiry. Read that header in both axios response interceptors and update localStorage.token so active users stay logged in. The header value uses the same `Bearer xxx` format the login endpoint returns, so it drops straight into the existing Authorization flow. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/frontend/src/api/request.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/api/request.tsx b/apps/frontend/src/api/request.tsx index 2a42e5ade..92088d058 100644 --- a/apps/frontend/src/api/request.tsx +++ b/apps/frontend/src/api/request.tsx @@ -6,12 +6,25 @@ import axios from 'axios'; import commonController from '@/utils/common'; import { goLogin } from '@/utils/sso'; +/** + * 滑动续期:后端在响应头 `X-New-Token` 中返回新签发的 token 时,更新本地存储, + * 使活跃用户的登录态自动延续,不会到点被强制登出。 + * @param response + */ +function applyRefreshedToken(response: AxiosResponse) { + const newToken = response?.headers?.['x-new-token']; + if (newToken) { + localStorage.token = newToken; + } +} + /** * 后端返回的结构由 { data, meta_data } 包裹 * @param response * @returns */ export function successHandler(response: AxiosResponse) { + applyRefreshedToken(response); return response.data; } @@ -79,7 +92,10 @@ const request = axios.create(requestConfig); export const requestWithHeaders = axios.create(requestConfig); requestWithHeaders.interceptors.request.use(authorizationBearerSuccess, authorizationBearerFailed); -requestWithHeaders.interceptors.response.use(undefined, authorizationBearerFailed); +requestWithHeaders.interceptors.response.use((response) => { + applyRefreshedToken(response); + return response; +}, authorizationBearerFailed); requestWithHeaders.interceptors.response.use(undefined, errorHandler); request.interceptors.request.use(authorizationBearerSuccess, authorizationBearerFailed);