From d7e41ec9ff2d2b38b6c2049acaafb3729d587309 Mon Sep 17 00:00:00 2001 From: jangrui Date: Sat, 1 Aug 2026 13:04:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20api-error=20=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=B8=9A=E5=8A=A1=E6=B6=88=E6=81=AF=E5=B9=B6?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=20pnpm=20=E6=9C=AC=E5=9C=B0=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 403 与 5xx 分支优先展示后端本地化业务消息(账号禁用、目录不可用、TLS 配置错误),无消息时回退通用文案 - .gitignore 增加 .pnpm-store/ Signed-off-by: jangrui --- .gitignore | 1 + .../auth/ldap/LdapIntegrationTest.java | 0 web/src/shared/lib/api-error.test.ts | 24 +++++++++++++++++++ web/src/shared/lib/api-error.ts | 8 +++++-- 4 files changed, 31 insertions(+), 2 deletions(-) mode change 100755 => 100644 server/skillhub-app/src/test/java/com/iflytek/skillhub/auth/ldap/LdapIntegrationTest.java diff --git a/.gitignore b/.gitignore index 3a6c5f5b..cff38ddf 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ target/ coverage/ dist/ node_modules/ +.pnpm-store/ *.tsbuildinfo package-lock.json diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/auth/ldap/LdapIntegrationTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/auth/ldap/LdapIntegrationTest.java old mode 100755 new mode 100644 diff --git a/web/src/shared/lib/api-error.test.ts b/web/src/shared/lib/api-error.test.ts index 5144fdf6..c30af2ee 100644 --- a/web/src/shared/lib/api-error.test.ts +++ b/web/src/shared/lib/api-error.test.ts @@ -57,6 +57,30 @@ describe('handleApiError', () => { expect(errorSpy).toHaveBeenLastCalledWith('Server said no') }) + it('shows the server message for 403 errors when present', async () => { + const { ApiError, handleApiError } = await import('./api-error') + + handleApiError(new ApiError('apiError.forbidden', 403, '账号已被禁用,请联系管理员')) + + expect(errorSpy).toHaveBeenLastCalledWith('账号已被禁用,请联系管理员') + }) + + it('shows the server message for 5xx errors when present', async () => { + const { ApiError, handleApiError } = await import('./api-error') + + handleApiError(new ApiError('apiError.serverError', 503, '目录服务器暂时不可用,请稍后重试')) + + expect(errorSpy).toHaveBeenLastCalledWith('目录服务器暂时不可用,请稍后重试') + }) + + it('falls back to generic text for 403/5xx without a server message', async () => { + const { ApiError, handleApiError } = await import('./api-error') + + handleApiError(new ApiError('apiError.forbidden', 403)) + + expect(errorSpy).toHaveBeenLastCalledWith(i18n.t('apiError.forbidden')) + }) + it('shows network error message when status is 0 (network disconnected)', async () => { const { ApiError, handleApiError } = await import('./api-error') diff --git a/web/src/shared/lib/api-error.ts b/web/src/shared/lib/api-error.ts index 03efebca..a743c94d 100644 --- a/web/src/shared/lib/api-error.ts +++ b/web/src/shared/lib/api-error.ts @@ -68,7 +68,9 @@ export function handleApiError(error: unknown): void { } if (status === 403) { - toast.error(i18n.t('apiError.forbidden')) + // The backend may attach a specific business message (e.g. a disabled account or an + // LDAP conflict); prefer it over the generic forbidden text. + toast.error(error.serverMessage || i18n.t('apiError.forbidden')) return } @@ -78,7 +80,9 @@ export function handleApiError(error: unknown): void { } if (status >= 500) { - toast.error(i18n.t('apiError.serverError')) + // The backend returns localized operational messages for service-level failures such as + // "directory unavailable" or "TLS misconfiguration"; surface them when present. + toast.error(error.serverMessage || i18n.t('apiError.serverError')) return }