diff --git a/rc-auth/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java b/rc-auth/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java new file mode 100644 index 00000000..ef3aa6ae --- /dev/null +++ b/rc-auth/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java @@ -0,0 +1,117 @@ +package com.red.circle.framework.feign.decoder; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.red.circle.framework.core.exception.ResponseException; +import com.red.circle.framework.core.request.ResponseHeaderConstant; +import com.red.circle.framework.core.response.ResponseErrorCode; +import com.red.circle.framework.core.spring.ApplicationContextUtils; +import com.red.circle.framework.dto.ResultResponse; +import com.red.circle.tool.core.http.HttpConstant; +import com.red.circle.tool.core.json.JacksonUtils; +import com.red.circle.tool.core.text.StringUtils; +import feign.Request; +import feign.Response; +import feign.codec.ErrorDecoder; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FeignErrorDecoder implements ErrorDecoder { + + private static final Logger log = LoggerFactory.getLogger(FeignErrorDecoder.class); + + private static final List PROCESS_RESULT_RESPONSE = List.of( + ResponseErrorCode.NOT_ACCEPTABLE.getCode(), + ResponseErrorCode.REQUEST_PARAMETER_ERROR.getCode() + ); + + @Override + public Exception decode(String methodKey, Response response) { + if (PROCESS_RESULT_RESPONSE.stream() + .anyMatch(code -> Objects.equals(response.status(), code))) { + ResponseException exception = parseResponseException(methodKey, response); + if (Objects.nonNull(exception)) { + return exception; + } + return createResponseException(methodKey, response); + } + + if (HttpConstant.is4xx(response.status())) { + return createResponseException(methodKey, response); + } + + if (ResponseHeaderConstant.existsHeaderValue(response.headers(), "RC-No-Retry", "true")) { + ResponseException exception = parseResponseException(methodKey, response); + if (Objects.nonNull(exception)) { + return exception; + } + return createResponseException(methodKey, response); + } + + return createResponseException(methodKey, response); + } + + private static String reqMapping(Response response) { + Request request = response.request(); + if (Objects.isNull(request)) { + return ""; + } + return request.httpMethod() + " " + request.url(); + } + + private ResponseException createResponseException(String methodKey, Response response) { + String errorCodeName = Objects.equals(response.status(), 429) + ? "REQ_LIMIT_INNER_DECODER" + : "ERROR_INNER_DECODER"; + return new ResponseException(response.status(), errorCodeName, getErrorMsg(methodKey, response)); + } + + private String getErrorMsg(String methodKey, Response response) { + return StringUtils.isBlankOrElse(response.reason(), "") + reqMapping(response); + } + + private ResponseException parseResponseException(String methodKey, Response response) { + ResultResponse responseBody = parseResponse(response); + if (Objects.nonNull(responseBody)) { + Map extValues = Optional.ofNullable(responseBody.getExtValues()) + .orElseGet(HashMap::new); + + extValues.put("innerError", + "[" + methodKey + "]" + StringUtils.isBlankOrElse(response.reason(), "")); + + return new ResponseException( + responseBody.getErrorCode(), + responseBody.getErrorCodeName(), + responseBody.getErrorMsg(), + extValues + ); + } + return null; + } + + private ResultResponse parseResponse(Response response) { + if (Objects.isNull(response.body())) { + log.warn("Feign error response body is null, status={}, reason={}, request={}", + response.status(), response.reason(), reqMapping(response)); + return null; + } + + try (InputStream inputStream = response.body().asInputStream()) { + String responseCompression = ApplicationContextUtils.getApplicationContext() + .getEnvironment() + .getProperty("spring.cloud.openfeign.compression.response.enabled"); + return JacksonUtils.readValue(inputStream, new TypeReference<>() { + }, Objects.equals(responseCompression, "true")); + } catch (IOException | RuntimeException ex) { + log.warn("Parse feign error response body failed, status={}, reason={}, request={}", + response.status(), response.reason(), reqMapping(response), ex); + return null; + } + } +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/annotation/aspect/CheckRegisterUserProfileProcess.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/annotation/aspect/CheckRegisterUserProfileProcess.java index ebb0b223..d4d9af0d 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/annotation/aspect/CheckRegisterUserProfileProcess.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/annotation/aspect/CheckRegisterUserProfileProcess.java @@ -12,18 +12,20 @@ import com.red.circle.tool.core.date.AgeUtils; import com.red.circle.tool.core.text.StringUtils; import com.red.circle.other.inner.model.cmd.user.UserProfileCmd; import com.red.circle.other.inner.model.cmd.user.account.CreateAccountCmd; -import java.util.Objects; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; /** * 检查注册资料信息,核对矫正等. * * @author pengliang on 2020/11/5 */ -@Component -@RequiredArgsConstructor -public class CheckRegisterUserProfileProcess { +@Component +@RequiredArgsConstructor +@Slf4j +public class CheckRegisterUserProfileProcess { private final OssServiceClient ossServiceClient; private final SysCountryCodeService sysCountryCodeService; @@ -32,7 +34,7 @@ public class CheckRegisterUserProfileProcess { UserProfileCmd profileCmd = cmd.getProfile(); setUserCountryInfo(profileCmd); calculationAge(profileCmd); - completeAvatarUrl(profileCmd); + completeAvatarUrl(cmd, profileCmd); checkGenerateDefaultNickname(profileCmd); } @@ -46,14 +48,29 @@ public class CheckRegisterUserProfileProcess { cmd.setUserNickname(KeywordConstant.filter(cmd.getUserNickname())); } - private void completeAvatarUrl(UserProfileCmd cmd) { - if (StringUtils.isNotBlank(cmd.getUserAvatar())) { - cmd.setUserAvatar(ResponseAssert.requiredSuccess( - ossServiceClient.processImgSaveAsCompressZoom(cmd.getUserAvatar(), - ImageSizeConst.COVER_HEIGHT) - )); - } - } + private void completeAvatarUrl(CreateAccountCmd accountCmd, UserProfileCmd cmd) { + if (StringUtils.isNotBlank(cmd.getUserAvatar())) { + String sourceAvatar = cmd.getUserAvatar(); + log.info( + "Register avatar process start, userId={}, type={}, openId={}, nickname={}, countryCode={}, source={}", + accountCmd.getReqUserId(), accountCmd.getType(), accountCmd.getOpenId(), + cmd.getUserNickname(), cmd.getCountryCode(), sourceAvatar); + try { + String processedAvatar = ResponseAssert.requiredSuccess( + ossServiceClient.processImgSaveAsCompressZoom(sourceAvatar, ImageSizeConst.COVER_HEIGHT) + ); + cmd.setUserAvatar(processedAvatar); + log.info("Register avatar process success, userId={}, source={}, target={}", + accountCmd.getReqUserId(), sourceAvatar, processedAvatar); + } catch (RuntimeException ex) { + log.error( + "Register avatar process failed, userId={}, type={}, openId={}, nickname={}, countryCode={}, source={}", + accountCmd.getReqUserId(), accountCmd.getType(), accountCmd.getOpenId(), + cmd.getUserNickname(), cmd.getCountryCode(), sourceAvatar, ex); + throw ex; + } + } + } // 计算年龄 private void calculationAge(UserProfileCmd cmd) { diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/user/UserAccountCommon.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/user/UserAccountCommon.java index a983b1e7..396bb907 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/user/UserAccountCommon.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/user/UserAccountCommon.java @@ -154,9 +154,17 @@ public class UserAccountCommon { return inviteUserInfo; } - private String requestUserSign(Long userId) { - return ResponseAssert.requiredSuccess(imAccountClient.createUserSig(userId)); - } + private String requestUserSign(Long userId) { + log.info("Register userSig create start, userId={}", userId); + try { + String userSig = ResponseAssert.requiredSuccess(imAccountClient.createUserSig(userId)); + log.info("Register userSig create success, userId={}", userId); + return userSig; + } catch (RuntimeException ex) { + log.error("Register userSig create failed, userId={}", userId, ex); + throw ex; + } + } private BaseInfo toBaseInfo(CreateAccountCmd cmd) { BaseInfo baseInfo = userProfileInfraConvertor.toBaseInfo(cmd.getProfile()); diff --git a/rc-service/rc-service-other/other-start/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java b/rc-service/rc-service-other/other-start/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java new file mode 100644 index 00000000..ef3aa6ae --- /dev/null +++ b/rc-service/rc-service-other/other-start/src/main/java/com/red/circle/framework/feign/decoder/FeignErrorDecoder.java @@ -0,0 +1,117 @@ +package com.red.circle.framework.feign.decoder; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.red.circle.framework.core.exception.ResponseException; +import com.red.circle.framework.core.request.ResponseHeaderConstant; +import com.red.circle.framework.core.response.ResponseErrorCode; +import com.red.circle.framework.core.spring.ApplicationContextUtils; +import com.red.circle.framework.dto.ResultResponse; +import com.red.circle.tool.core.http.HttpConstant; +import com.red.circle.tool.core.json.JacksonUtils; +import com.red.circle.tool.core.text.StringUtils; +import feign.Request; +import feign.Response; +import feign.codec.ErrorDecoder; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FeignErrorDecoder implements ErrorDecoder { + + private static final Logger log = LoggerFactory.getLogger(FeignErrorDecoder.class); + + private static final List PROCESS_RESULT_RESPONSE = List.of( + ResponseErrorCode.NOT_ACCEPTABLE.getCode(), + ResponseErrorCode.REQUEST_PARAMETER_ERROR.getCode() + ); + + @Override + public Exception decode(String methodKey, Response response) { + if (PROCESS_RESULT_RESPONSE.stream() + .anyMatch(code -> Objects.equals(response.status(), code))) { + ResponseException exception = parseResponseException(methodKey, response); + if (Objects.nonNull(exception)) { + return exception; + } + return createResponseException(methodKey, response); + } + + if (HttpConstant.is4xx(response.status())) { + return createResponseException(methodKey, response); + } + + if (ResponseHeaderConstant.existsHeaderValue(response.headers(), "RC-No-Retry", "true")) { + ResponseException exception = parseResponseException(methodKey, response); + if (Objects.nonNull(exception)) { + return exception; + } + return createResponseException(methodKey, response); + } + + return createResponseException(methodKey, response); + } + + private static String reqMapping(Response response) { + Request request = response.request(); + if (Objects.isNull(request)) { + return ""; + } + return request.httpMethod() + " " + request.url(); + } + + private ResponseException createResponseException(String methodKey, Response response) { + String errorCodeName = Objects.equals(response.status(), 429) + ? "REQ_LIMIT_INNER_DECODER" + : "ERROR_INNER_DECODER"; + return new ResponseException(response.status(), errorCodeName, getErrorMsg(methodKey, response)); + } + + private String getErrorMsg(String methodKey, Response response) { + return StringUtils.isBlankOrElse(response.reason(), "") + reqMapping(response); + } + + private ResponseException parseResponseException(String methodKey, Response response) { + ResultResponse responseBody = parseResponse(response); + if (Objects.nonNull(responseBody)) { + Map extValues = Optional.ofNullable(responseBody.getExtValues()) + .orElseGet(HashMap::new); + + extValues.put("innerError", + "[" + methodKey + "]" + StringUtils.isBlankOrElse(response.reason(), "")); + + return new ResponseException( + responseBody.getErrorCode(), + responseBody.getErrorCodeName(), + responseBody.getErrorMsg(), + extValues + ); + } + return null; + } + + private ResultResponse parseResponse(Response response) { + if (Objects.isNull(response.body())) { + log.warn("Feign error response body is null, status={}, reason={}, request={}", + response.status(), response.reason(), reqMapping(response)); + return null; + } + + try (InputStream inputStream = response.body().asInputStream()) { + String responseCompression = ApplicationContextUtils.getApplicationContext() + .getEnvironment() + .getProperty("spring.cloud.openfeign.compression.response.enabled"); + return JacksonUtils.readValue(inputStream, new TypeReference<>() { + }, Objects.equals(responseCompression, "true")); + } catch (IOException | RuntimeException ex) { + log.warn("Parse feign error response body failed, status={}, reason={}, request={}", + response.status(), response.reason(), reqMapping(response), ex); + return null; + } + } +}