fegin报错传递
This commit is contained in:
@@ -26,7 +26,7 @@ public class BuyerAccountController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
@Operation(summary = "注册")
|
@Operation(summary = "获取验证码后注册")
|
||||||
public Boolean register(@Valid @RequestBody RegisterDTO dto) {
|
public Boolean register(@Valid @RequestBody RegisterDTO dto) {
|
||||||
return buyerAccountService.register(dto);
|
return buyerAccountService.register(dto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package com.aida.buyer.module.feign.config;
|
package com.aida.buyer.module.feign.config;
|
||||||
|
|
||||||
|
import com.aida.buyer.module.feign.decoder.BusinessErrorFeignDecoder;
|
||||||
import com.aida.buyer.module.feign.interceptor.InternalCallInterceptor;
|
import com.aida.buyer.module.feign.interceptor.InternalCallInterceptor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import feign.RequestInterceptor;
|
import feign.RequestInterceptor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Feign 全局配置:注册所有 Feign 拦截器。
|
* Feign 全局配置:注册所有 Feign 拦截器和 Decoder。
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class FeignConfig {
|
public class FeignConfig {
|
||||||
@@ -15,4 +17,9 @@ public class FeignConfig {
|
|||||||
public RequestInterceptor internalCallInterceptor() {
|
public RequestInterceptor internalCallInterceptor() {
|
||||||
return new InternalCallInterceptor();
|
return new InternalCallInterceptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BusinessErrorFeignDecoder businessErrorFeignDecoder(ObjectMapper objectMapper) {
|
||||||
|
return new BusinessErrorFeignDecoder(objectMapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.aida.buyer.module.feign.decoder;
|
||||||
|
|
||||||
|
import com.aida.buyer.common.exception.BusinessException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import feign.FeignException;
|
||||||
|
import feign.Request;
|
||||||
|
import feign.Response;
|
||||||
|
import feign.codec.DecodeException;
|
||||||
|
import feign.codec.Decoder;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feign 全局 Decoder。
|
||||||
|
*
|
||||||
|
* <p>背景:seller 端使用 {@code @RestControllerAdvice} 将 {@code BusinessException}
|
||||||
|
* 转为 HTTP 200 + {@code Response.fail(code, msg)} 返回。
|
||||||
|
* 默认 Decoder 只看 HTTP 状态码,2xx 一律视为成功,导致 buyer 端无法感知远程业务错误。</p>
|
||||||
|
*
|
||||||
|
* <p>本 Decoder 在解析响应体时:
|
||||||
|
* <ul>
|
||||||
|
* <li>若 HTTP 状态码为 2xx,先将 body 读取为字符串并解析为标准 {@code Response};</li>
|
||||||
|
* <li>若 {@code errCode != 0},抛出 {@link BusinessException},错误信息为远程返回的 errMsg;</li>
|
||||||
|
* <li>否则使用 {@link ObjectMapper} 将 body 反序列化为目标类型 {@code T}。</li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>HTTP 非 2xx 状态码(如 500、服务不可用)由 Feign 默认 ErrorDecoder 抛出
|
||||||
|
* {@link FeignException},不在本 Decoder 处理范围内。</p>
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BusinessErrorFeignDecoder implements Decoder {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
|
||||||
|
if (!is2xx(response.status())) {
|
||||||
|
throw FeignException.errorStatus(requestKey(response), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
String body = readBody(response);
|
||||||
|
if (body == null || body.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先按标准 Response 格式解析,校验 errCode
|
||||||
|
com.aida.buyer.common.result.Response<?> genericResp = objectMapper.readValue(body, com.aida.buyer.common.result.Response.class);
|
||||||
|
if (genericResp.getErrCode() != 0) {
|
||||||
|
throw new BusinessException(
|
||||||
|
genericResp.getErrCode(),
|
||||||
|
genericResp.getErrMsg() != null ? genericResp.getErrMsg() : "远程服务业务错误"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// errCode == 0,ObjectMapper 反序列化为目标类型
|
||||||
|
return objectMapper.readValue(body, objectMapper.getTypeFactory().constructType(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean is2xx(int status) {
|
||||||
|
return status >= 200 && status < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readBody(Response response) throws IOException {
|
||||||
|
if (response.body() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(response.body().asInputStream(), StandardCharsets.UTF_8))) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requestKey(Response response) {
|
||||||
|
Request request = response.request();
|
||||||
|
return request.method() + " " + request.url();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.aida.buyer.module.order.service.impl;
|
package com.aida.buyer.module.order.service.impl;
|
||||||
|
|
||||||
import com.aida.buyer.common.context.UserContext;
|
import com.aida.buyer.common.context.UserContext;
|
||||||
import com.aida.buyer.common.exception.BusinessException;
|
|
||||||
import com.aida.buyer.common.result.PageResponse;
|
import com.aida.buyer.common.result.PageResponse;
|
||||||
import com.aida.buyer.common.result.Response;
|
import com.aida.buyer.common.result.Response;
|
||||||
import com.aida.buyer.module.account.entity.BuyerAccount;
|
import com.aida.buyer.module.account.entity.BuyerAccount;
|
||||||
@@ -46,10 +45,6 @@ public class BuyerOrderServiceImpl implements IBuyerOrderService {
|
|||||||
dto.setBuyerUsername(account.getUsername());
|
dto.setBuyerUsername(account.getUsername());
|
||||||
|
|
||||||
Response<CreateOrderResultVO> orderResp = orderFeignClient.createOrder(dto);
|
Response<CreateOrderResultVO> orderResp = orderFeignClient.createOrder(dto);
|
||||||
if (orderResp == null || orderResp.getErrCode() != 0) {
|
|
||||||
throw new BusinessException("创建订单失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateOrderResultVO result = orderResp.getData();
|
CreateOrderResultVO result = orderResp.getData();
|
||||||
// TODO:调用支付模块,传入buyerId,result.getOrderIds(),result.getTotalAmount()
|
// TODO:调用支付模块,传入buyerId,result.getOrderIds(),result.getTotalAmount()
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
nacos:
|
nacos:
|
||||||
namespace: ltx
|
namespace: dev
|
||||||
host: 18.167.251.121:28848
|
host: 18.167.251.121:28848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: Aidlab123123!
|
password: Aidlab123123!
|
||||||
|
|||||||
Reference in New Issue
Block a user