Compare commits

..

2 Commits

Author SHA1 Message Date
wangxiu 9e0729f6f5 修改系统内部异常的响应结构体 2026-07-10 23:46:58 +08:00
wangxiu ba38fbf0cc 命中缓存,更新 responseId 2026-07-10 23:44:58 +08:00
4 changed files with 59 additions and 21 deletions

View File

@ -1,17 +1,31 @@
package com.lyxh.api.docking.exception; package com.lyxh.api.docking.exception;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.time.Instant; import org.apache.commons.codec.digest.DigestUtils;
import java.util.UUID;
@Data @Data
public class ErrorResponse { public class ErrorResponse {
private final String error;
private final String message;
private final String timestamp;
public ErrorResponse(String error, String message) { private final String code;
this.error = error; private final String message;
private final String responseId;
private final DataNode data;
public ErrorResponse(String code, String message) {
this.code = code;
this.message = message; this.message = message;
this.timestamp = Instant.now().toString(); this.responseId = DigestUtils.md5Hex(UUID.randomUUID().toString());
this.data = new DataNode();
}
@Data
public static class DataNode {
private final int status = 0;
@JsonProperty("result")
private final Object result = null;
} }
} }

View File

@ -20,7 +20,7 @@ public class GlobalExceptionHandler {
.reduce((a, b) -> a + "; " + b) .reduce((a, b) -> a + "; " + b)
.orElse("validation failed"); .orElse("validation failed");
return ResponseEntity.badRequest() return ResponseEntity.badRequest()
.body(new ErrorResponse("VALIDATION_ERROR", msg)); .body(new ErrorResponse("400", msg));
} }
@ExceptionHandler(ApiCallException.class) @ExceptionHandler(ApiCallException.class)
@ -34,13 +34,13 @@ public class GlobalExceptionHandler {
String detail = ex.getResponseBody() != null && !ex.getResponseBody().isEmpty() String detail = ex.getResponseBody() != null && !ex.getResponseBody().isEmpty()
? ex.getResponseBody() : ex.getMessage(); ? ex.getResponseBody() : ex.getMessage();
return ResponseEntity.status(status) return ResponseEntity.status(status)
.body(new ErrorResponse(ex.getCode(), detail)); .body(new ErrorResponse(String.valueOf(status.value()), detail));
} }
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneral(Exception ex) { public ResponseEntity<ErrorResponse> handleGeneral(Exception ex) {
log.error("Unexpected error", ex); log.error("Unexpected error", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL_ERROR", "Internal server error")); .body(new ErrorResponse("500", "Internal server error"));
} }
} }

View File

@ -1,9 +1,13 @@
package com.lyxh.api.docking.service; package com.lyxh.api.docking.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lyxh.api.docking.client.ApiCallResult; import com.lyxh.api.docking.client.ApiCallResult;
import com.lyxh.api.docking.client.GenericApiClient; import com.lyxh.api.docking.client.GenericApiClient;
import com.lyxh.api.docking.entity.ApiCacheData; import com.lyxh.api.docking.entity.ApiCacheData;
import com.lyxh.api.docking.entity.ThirdPartyConfig; import com.lyxh.api.docking.entity.ThirdPartyConfig;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -11,6 +15,7 @@ import org.springframework.stereotype.Service;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@ -32,6 +37,9 @@ public class GenericApiService {
@Autowired @Autowired
private ApiInvokeLogService invokeLogService; private ApiInvokeLogService invokeLogService;
@Autowired
private ObjectMapper objectMapper;
/** /**
* 执行第三方 API 调用(含缓存、日志),返回响应体原始 JSON * 执行第三方 API 调用(含缓存、日志),返回响应体原始 JSON
* *
@ -65,7 +73,19 @@ public class GenericApiService {
ApiCacheData cached = cacheDataService.getNonExpiredCache(apiCode, cacheKey, config.getId()); ApiCacheData cached = cacheDataService.getNonExpiredCache(apiCode, cacheKey, config.getId());
if (cached != null) { if (cached != null) {
log.info("Cache hit: weOrderNo={} apiCode={} cacheKey={}", weOrderNo, apiCode, cacheKey); log.info("Cache hit: weOrderNo={} apiCode={} cacheKey={}", weOrderNo, apiCode, cacheKey);
return cached.getCacheValue(); // 命中缓存,更新 responseId
String cacheValue = cached.getCacheValue();
try {
JsonNode root = objectMapper.readTree(cacheValue);
if (root.has("responseId")) {
String newResponseId = DigestUtils.md5Hex(UUID.randomUUID().toString());
((ObjectNode) root).put("responseId", newResponseId);
return objectMapper.writeValueAsString(root);
}
} catch (Exception e) {
log.warn("Failed to replace responseId in cached response: weOrderNo={}", weOrderNo, e);
}
return cacheValue;
} }
log.info("Cache miss: weOrderNo={} apiCode={} cacheKey={}", weOrderNo, apiCode, cacheKey); log.info("Cache miss: weOrderNo={} apiCode={} cacheKey={}", weOrderNo, apiCode, cacheKey);
} }

View File

@ -105,22 +105,26 @@
## 错误响应 ## 错误响应
统一错误格式: 错误响应与三方接口响应保持相同结构,其中`data` 中 `status=0`、`result=null`:
```json ```json
{ {
"error": "ERROR_CODE", "code": "503",
"message": "错误描述", "message": "External API unreachable after 1 attempts",
"timestamp": "2026-07-08T10:30:00Z" "responseId": "a1b2c3d4e5f6789012345678abcdef01",
"data": {
"status": 0,
"result": null
}
} }
``` ```
| HTTP状态码 | error | 说明 | | HTTP状态码 | code | 说明 |
|---|---|------------------| |---|---|---|
| 400 | VALIDATION_ERROR | 请求参数校验失败 | | 400 | 400 | 请求参数校验失败 |
| 502 | HTTP_ERROR | 三方 API HTTP 错误 | | 502 | 502 | 三方 API HTTP 错误 |
| 503 | NETWORK_ERROR | 三方 API 网络不可达 | | 503 | 503 | 三方 API 网络不可达 |
| 500 | INTERNAL_ERROR | 服务内部未知异常 api配置信息未找到 | | 500 | 500 | 服务内部未知异常 |
## 完整调用示例 ## 完整调用示例