Add registration failure diagnostics

This commit is contained in:
hy001 2026-05-18 10:54:54 +08:00
parent b057119fd3
commit 7d1909858e
4 changed files with 277 additions and 18 deletions

View File

@ -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<Integer> 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<Void> responseBody = parseResponse(response);
if (Objects.nonNull(responseBody)) {
Map<String, Object> 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<Void> 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;
}
}
}

View File

@ -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) {

View File

@ -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());

View File

@ -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<Integer> 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<Void> responseBody = parseResponse(response);
if (Objects.nonNull(responseBody)) {
Map<String, Object> 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<Void> 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;
}
}
}