From fcc3555fc90dc76efd9b3d73cfb1440dc818abbe Mon Sep 17 00:00:00 2001 From: xxzuo <1293378490@qq.com> Date: Sat, 31 Jan 2026 10:37:02 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E4=BC=98=E5=8C=96=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86=E5=92=8CHTTP=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在DataVinesExceptionHandler中添加token刷新逻辑重构 - 实现HTTP响应拦截器中的错误消息国际化功能 - 添加中英文HTTP错误状态码对应的消息提示 - 集成前端HTTP错误处理与后端token刷新机制 - 增强网络错误、超时错误和HTTP状态码错误的处理能力 --- .../inteceptor/DataVinesExceptionHandler.java | 34 ++++++-- .../Editor/http/response.interceptor.ts | 81 ++++++++++++++++++- datavines-ui/src/http/index.ts | 2 + datavines-ui/src/locale/en_US.ts | 15 +++- datavines-ui/src/locale/zh_CN.ts | 15 +++- 5 files changed, 136 insertions(+), 11 deletions(-) diff --git a/datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java b/datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java index d380dddfb..9cb7891fd 100644 --- a/datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java +++ b/datavines-server/src/main/java/io/datavines/server/api/inteceptor/DataVinesExceptionHandler.java @@ -16,12 +16,14 @@ */ package io.datavines.server.api.inteceptor; +import io.datavines.core.constant.DataVinesConstants; import io.datavines.core.entity.ResultMap; import io.datavines.core.enums.Status; import io.datavines.core.utils.TokenManager; import io.datavines.core.exception.DataVinesServerException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; @@ -58,10 +60,12 @@ public ResponseEntity dataVinesServerExceptionHandler(DataVinesServer return ResponseEntity.ok(new ResultMap().fail(Status.PLEASE_LOGIN.getCode()).message(Status.PLEASE_LOGIN.getMsg())); } - if (!Objects.isNull(status) ) { + if (!Objects.isNull(status)) { resultMap.fail(status.getCode()); + } else { + resultMap.fail(); } - resultMap.failAndRefreshToken(request); + tryRefreshToken(request, resultMap); resultMap.message(e.getMessage()); return ResponseEntity.ok(resultMap); } @@ -70,7 +74,8 @@ public ResponseEntity dataVinesServerExceptionHandler(DataVinesServer public ResponseEntity constraintViolationExceptionHandler(Exception e, HttpServletRequest request) { log.error("ConstraintViolationException:", e); ResultMap resultMap = new ResultMap(tokenManager); - resultMap.failAndRefreshToken(request); + resultMap.fail(); + tryRefreshToken(request, resultMap); resultMap.message(buildValidFailMessage((ConstraintViolationException) e)); return ResponseEntity.ok(resultMap); } @@ -79,7 +84,8 @@ public ResponseEntity constraintViolationExceptionHandler(Exception e public ResponseEntity methodArgumentNotValidExceptionHandler(Exception e, HttpServletRequest request) { log.error("MethodArgumentNotValidException:", e); ResultMap resultMap = new ResultMap(tokenManager); - resultMap.failAndRefreshToken(request); + resultMap.fail(); + tryRefreshToken(request, resultMap); String message = buildValidFailMessage((MethodArgumentNotValidException) e); resultMap.message(message); return ResponseEntity.ok(resultMap); @@ -89,11 +95,29 @@ public ResponseEntity methodArgumentNotValidExceptionHandler(Exceptio public ResponseEntity commonExceptionHandler(Exception e, HttpServletRequest request) { log.error("Exception:", e); ResultMap resultMap = new ResultMap(tokenManager); - resultMap.failAndRefreshToken(request); + resultMap.fail(); + tryRefreshToken(request, resultMap); resultMap.message(e.getMessage()); return ResponseEntity.ok(resultMap); } + private void tryRefreshToken(HttpServletRequest request, ResultMap resultMap) { + try { + String token = request.getHeader(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = (String) request.getAttribute(DataVinesConstants.TOKEN_HEADER_STRING); + if (StringUtils.isEmpty(token)) { + token = request.getParameter(DataVinesConstants.TOKEN_HEADER_STRING); + } + } + if (StringUtils.isNotEmpty(token) && tokenManager != null) { + resultMap.put("token", tokenManager.refreshToken(token)); + } + } catch (Exception ex) { + log.debug("Token refresh skipped: {}", ex.getMessage()); + } + } + private String buildValidFailMessage(ConstraintViolationException violationException) { Set> constraintViolationSet = violationException.getConstraintViolations(); StringBuilder messageBuilder = new StringBuilder(); diff --git a/datavines-ui/Editor/http/response.interceptor.ts b/datavines-ui/Editor/http/response.interceptor.ts index 29d7a8b17..559df2e93 100644 --- a/datavines-ui/Editor/http/response.interceptor.ts +++ b/datavines-ui/Editor/http/response.interceptor.ts @@ -1,6 +1,49 @@ /* eslint-disable prefer-promise-reject-errors */ import { IResponseInterface } from './type'; +// Current locale for i18n error messages +let currentLocale = 'en_US'; + +// Set locale for error messages +export const setHttpErrorLocale = (locale: string) => { + currentLocale = locale; +}; + +// i18n error messages +const errorMessages: Record> = { + zh_CN: { + network: '网络连接失败,无法连接到服务器', + timeout: '请求超时,请检查网络后重试', + 400: '请求参数错误', + 401: '未授权,请先登录', + 403: '访问被拒绝', + 404: '资源不存在', + 500: '服务器内部错误', + 502: '网关错误', + 503: '服务暂时不可用', + 504: '网关超时', + unknown: '服务器错误', + }, + en_US: { + network: 'Network connection failed, unable to connect to server', + timeout: 'Request timeout, please check your network', + 400: 'Bad request', + 401: 'Unauthorized, please login', + 403: 'Access denied', + 404: 'Resource not found', + 500: 'Internal server error', + 502: 'Gateway error', + 503: 'Service unavailable', + 504: 'Gateway timeout', + unknown: 'Server error', + }, +}; + +const getErrorMessage = (key: string): string => { + const messages = errorMessages[currentLocale] || errorMessages.en_US; + return messages[key] || messages.unknown; +}; + export const responseOnSuccess = (response: IResponseInterface) => { const { data } = response; if (data) { @@ -19,14 +62,44 @@ export const responseOnSuccess = (response: IResponseInterface) => { code: data?.code, }); }; -export const responseOnError = (error: any):any => { - console.log(error); + +export const responseOnError = (error: any): any => { + console.log('Response error:', error); // eslint-disable-next-line no-underscore-dangle if (error?.__CANCEL__) { return; } + + // Server returned HTTP error (e.g., 500) + if (error.response) { + const { status, data } = error.response; + + // Prefer backend error message if available + if (data && data.msg) { + return Promise.reject({ + msg: data.msg, + code: data.code || status, + }); + } + + // HTTP status code error without structured message + return Promise.reject({ + msg: getErrorMessage(String(status)), + code: status, + }); + } + + // Timeout error + if (error.code === 'ECONNABORTED' || error.message?.includes('timeout')) { + return Promise.reject({ + msg: getErrorMessage('timeout'), + code: 'TIMEOUT', + }); + } + + // Network error (unable to connect to server) return Promise.reject({ - msg: error?.msg || 'interface error', - code: null, + msg: getErrorMessage('network'), + code: 'NETWORK_ERROR', }); }; diff --git a/datavines-ui/src/http/index.ts b/datavines-ui/src/http/index.ts index b76159311..5eef99c63 100644 --- a/datavines-ui/src/http/index.ts +++ b/datavines-ui/src/http/index.ts @@ -1,4 +1,5 @@ import { getHttp } from '@Editor/http'; +import { setHttpErrorLocale } from '@Editor/http/response.interceptor'; import { createHashHistory } from 'history'; import shareData from 'src/utils/shareData'; import { DV_STORAGE_LOGIN } from 'src/utils/constants'; @@ -32,6 +33,7 @@ export const $http = getHttp({ } if (locale) { config.headers.language = locale; + setHttpErrorLocale(locale); } return config; }, diff --git a/datavines-ui/src/locale/en_US.ts b/datavines-ui/src/locale/en_US.ts index 2919d4a24..0a1f8338c 100644 --- a/datavines-ui/src/locale/en_US.ts +++ b/datavines-ui/src/locale/en_US.ts @@ -359,5 +359,18 @@ export default { dv_flink_deploy_mode_yarn_application: 'Yarn Application Mode', dv_deploy_mode_cluster: 'Cluster Mode', dv_deploy_mode_yarn: 'Yarn Mode', - dv_deploy_mode_local: 'Local Mode' + dv_deploy_mode_local: 'Local Mode', + + // HTTP error messages + http_error_network: 'Network connection failed, unable to connect to server', + http_error_timeout: 'Request timeout, please check your network', + http_error_400: 'Bad request', + http_error_401: 'Unauthorized, please login', + http_error_403: 'Access denied', + http_error_404: 'Resource not found', + http_error_500: 'Internal server error', + http_error_502: 'Gateway error', + http_error_503: 'Service unavailable', + http_error_504: 'Gateway timeout', + http_error_unknown: 'Server error' }; diff --git a/datavines-ui/src/locale/zh_CN.ts b/datavines-ui/src/locale/zh_CN.ts index 7ec2a4b67..be56ce033 100644 --- a/datavines-ui/src/locale/zh_CN.ts +++ b/datavines-ui/src/locale/zh_CN.ts @@ -361,5 +361,18 @@ export default { dv_flink_deploy_mode_yarn_application: 'Yarn Application模式', dv_deploy_mode_cluster: '集群模式', dv_deploy_mode_yarn: 'Yarn模式', - dv_deploy_mode_local: '本地模式' + dv_deploy_mode_local: '本地模式', + + // HTTP error messages + http_error_network: '网络连接失败,无法连接到服务器', + http_error_timeout: '请求超时,请检查网络后重试', + http_error_400: '请求参数错误', + http_error_401: '未授权,请先登录', + http_error_403: '访问被拒绝', + http_error_404: '资源不存在', + http_error_500: '服务器内部错误', + http_error_502: '网关错误', + http_error_503: '服务暂时不可用', + http_error_504: '网关超时', + http_error_unknown: '服务器错误' };