diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultCredential.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultCredential.java index 47e740c..a9eaef5 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultCredential.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultCredential.java @@ -5,7 +5,6 @@ import com.czcb.scfs.api.core.http.HttpHeaders; import com.czcb.scfs.api.core.http.HttpRequest; import com.czcb.scfs.api.core.http.OriginalResponse; import com.czcb.scfs.api.core.util.DateTimes; -import com.czcb.scfs.api.core.util.Nonce; import com.czcb.scfs.api.core.util.Strings; import java.util.Map; @@ -33,7 +32,7 @@ public class DefaultCredential implements Credential { } private void addNecessityCustomizeHeaders(HttpRequest request) { - request.getHttpHeaders().addHeader(NONCE, Nonce.ofNonce()); + request.getHttpHeaders().addHeader(NONCE, request.getId()); request.getHttpHeaders().addHeader(TIMESTAMP, DateTimes.ofTimestamp()); } diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java index ca7f8b2..702b6b0 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java @@ -5,6 +5,7 @@ import com.czcb.scfs.api.core.Profile; import com.czcb.scfs.api.core.exception.TimestampException; import com.czcb.scfs.api.core.exception.ValidationException; import com.czcb.scfs.api.core.http.HttpLogger; +import com.czcb.scfs.api.core.http.HttpRequest; import com.czcb.scfs.api.core.http.OriginalResponse; import com.czcb.scfs.api.core.util.Strings; @@ -36,7 +37,7 @@ public final class DefaultValidator implements Validator { return httpCode < HTTP_OK || httpCode >= HTTP_MULT_CHOICE; } - private void validateTimestamp(OriginalResponse response) { + private void validateTimestamp(HttpRequest request, OriginalResponse response) { try { String timestamp = response.getHttpHeaders().getHeader(TIMESTAMP); if (Strings.isEmpty(timestamp)) { @@ -51,19 +52,19 @@ public final class DefaultValidator implements Validator { timestamp, response.getHttpHeaders().getHeader(REQUEST_ID))); } } catch (Exception e) { - httpLogger.logResponseError(response); + httpLogger.logResponseError(request, response); throw new TimestampException(e.getMessage(), e); } } @Override - public void validate(OriginalResponse response, Channel channel) { + public void validate(HttpRequest request, OriginalResponse response, Channel channel) { if (isInvalidHttpCode(response.getStatusCode())) { httpLogger.logHttpStatus(response); } // 校验时间戳 - validateTimestamp(response); + validateTimestamp(request, response); // 请求头包含 SecretKey 进行验签 if (!headerContainsSecretKey(response)) { @@ -80,7 +81,7 @@ public final class DefaultValidator implements Validator { } if (!verifier.verify(null, message, signature)) { - httpLogger.logResponseError(response); + httpLogger.logResponseError(request, response); throw new ValidationException(String.format("响应校验失败, 签名校验未通过, Request-Id=%s", response.getHttpHeaders().getHeader(REQUEST_ID))); } diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/Validator.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/Validator.java index 795cf3e..1741b21 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/Validator.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/Validator.java @@ -1,6 +1,7 @@ package com.czcb.scfs.api.core.cipher; import com.czcb.scfs.api.core.Channel; +import com.czcb.scfs.api.core.http.HttpRequest; import com.czcb.scfs.api.core.http.OriginalResponse; /** @@ -12,5 +13,5 @@ public interface Validator { /** * 验证返回是否合法 */ - void validate(OriginalResponse response, Channel channel); + void validate(HttpRequest request, OriginalResponse response, Channel channel); } diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java index d74a63a..de89fd6 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java @@ -68,18 +68,19 @@ public abstract class AbstractApiClient implements ApiClient { // 实际调用 originalResponse = doRemoteExecute(newRequest); } catch (Exception e) { + httpLogger.logRemoteError(newRequest, e.getMessage()); throw new ApiClientException(e); } finally { watch.stop(); } // 校验响应 - OriginalResponse resultfulResponse = validateResponse(originalResponse); + OriginalResponse resultfulResponse = validateResponse(newRequest, originalResponse); // 解析返回数据 HttpResponse httpResponse = assembleHttpResponse(resultfulResponse, responseClass); // 打印响应结果 - httpLogger.logResponse(originalResponse, httpResponse, watch.getLastTaskTimeMillis()); + httpLogger.logResponse(newRequest, originalResponse, httpResponse, watch.getLastTaskTimeMillis()); return httpResponse; } @@ -94,6 +95,7 @@ public abstract class AbstractApiClient implements ApiClient { request = httpRequestEncrypt(request); // 组合请求数据 HttpRequest.Builder builder = new HttpRequest.Builder() + .id(request.getId()) .url(fullUrlPattern(request)) .httpMethod(request.getHttpMethod()) .addHeader(AUTHORIZATION, getAuthorization(request)) @@ -172,8 +174,8 @@ public abstract class AbstractApiClient implements ApiClient { * @param originalResponse OriginalResponse * @return OriginalResponse */ - private OriginalResponse validateResponse(OriginalResponse originalResponse) { - validator.validate(originalResponse, getProfile().getChannel()); + private OriginalResponse validateResponse(HttpRequest request, OriginalResponse originalResponse) { + validator.validate(request, originalResponse, getProfile().getChannel()); return originalResponse; } diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpLogger.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpLogger.java index fb04324..3c3e438 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpLogger.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpLogger.java @@ -28,19 +28,19 @@ public class HttpLogger { return; } - logger.info("请求行:{} {} {}", request.getHttpMethod(), request.getUrl(), httpVersion); + logger.info("[{}] 请求行:{} {} {}", request.getId(), request.getHttpMethod(), request.getUrl(), httpVersion); StringBuilder sb = new StringBuilder(); request.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); - logger.info("请求头:{}", Strings.removeSuffix(sb.toString(), ";")); + logger.info("[{}] 请求头:{}", request.getId(), Strings.removeSuffix(sb.toString(), ";")); if (request.getRequestBody() instanceof EncryptRequestBody) { EncryptRequestBody body = (EncryptRequestBody) request.getRequestBody(); - logger.info("请求原始报文:{}", Strings.toStr(body.getOriginalBody())); - logger.info("请求加密报文:{}", Strings.toStr(body.getBody())); + logger.info("[{}] 请求原始报文:{}", request.getId(), Strings.toStr(body.getOriginalBody())); + logger.info("[{}] 请求加密报文:{}", request.getId(), Strings.toStr(body.getBody())); } else if (request.getRequestBody() instanceof JsonRequestBody) { JsonRequestBody body = (JsonRequestBody) request.getRequestBody(); - logger.info("请求原始报文:{}", Strings.toStr(body.getBody())); + logger.info("[{}] 请求原始报文:{}", request.getId(), Strings.toStr(body.getBody())); } } @@ -52,19 +52,19 @@ public class HttpLogger { * @param duration 请求耗时 * @param 返回类型 */ - protected void logResponse(OriginalResponse originalResponse, HttpResponse response, long duration) { + protected void logResponse(HttpRequest request, OriginalResponse originalResponse, HttpResponse response, long duration) { if (!logEnabled) { return; } - logger.info("响应行:{} {}", originalResponse.getVersion(), originalResponse.getStatusCode()); + logger.info("[{}] 响应行:{} {}", request.getId(), originalResponse.getVersion(), originalResponse.getStatusCode()); StringBuilder sb = new StringBuilder(); response.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); - logger.info("响应头:{}", Strings.removeSuffix(sb.toString(), ";")); - logger.info("响应原始报文:{}", Strings.toStr(response.getOriginalBody())); - logger.info("响应解密报文:{}", Json.toJson(response.getServiceResponse())); + logger.info("[{}] 响应头:{}", request.getId(), Strings.removeSuffix(sb.toString(), ";")); + logger.info("[{}] 响应原始报文:{}", request.getId(), Strings.toStr(response.getOriginalBody())); + logger.info("[{}] 响应解密报文:{}", request.getId(), Json.toJson(response.getServiceResponse())); - logger.info("请求-响应耗时(毫秒):{}", duration); + logger.info("[{}] 请求-响应耗时(毫秒):{}", request.getId(), duration); } /** @@ -72,15 +72,19 @@ public class HttpLogger { * * @param originalResponse 响应数据 */ - public void logResponseError(OriginalResponse originalResponse) { - logger.info("响应:{} {}", originalResponse.getVersion(), originalResponse.getStatusCode()); + public void logResponseError(HttpRequest request, OriginalResponse originalResponse) { + logger.error("[{}] 响应:{} {}", request.getId(), originalResponse.getVersion(), originalResponse.getStatusCode()); StringBuilder sb = new StringBuilder(); originalResponse.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); - logger.info("响应头:{}", Strings.removeSuffix(sb.toString(), ";")); - logger.info("响应原始报文:{}", Strings.toStr((originalResponse.getBody()))); + logger.error("[{}] 响应头:{}", request.getId(), Strings.removeSuffix(sb.toString(), ";")); + logger.error("[{}] 响应原始报文:{}", request.getId(), Strings.toStr((originalResponse.getBody()))); } public void logHttpStatus(OriginalResponse response) { // TODO 打印状态码说明 } + + public void logRemoteError(HttpRequest newRequest, String message) { + logger.error("[{}] 远程调用异常:{}", newRequest.getId(), message); + } } diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpRequest.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpRequest.java index c6fc1e7..5e5634a 100644 --- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpRequest.java +++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/HttpRequest.java @@ -1,5 +1,8 @@ package com.czcb.scfs.api.core.http; +import com.czcb.scfs.api.core.util.Nonce; +import com.czcb.scfs.api.core.util.Strings; + import java.util.Map; import java.util.Objects; @@ -14,6 +17,9 @@ import static java.util.Objects.requireNonNull; * @since 2.0.0 */ public class HttpRequest { + // 请求Id + private final String id; + // http 请求方法 private final HttpMethod httpMethod; // 地址 @@ -27,6 +33,10 @@ public class HttpRequest { // 是否开启压缩 private final boolean compression; + public String getId() { + return id; + } + public HttpMethod getHttpMethod() { return httpMethod; } @@ -53,6 +63,7 @@ public class HttpRequest { public Builder newBuilder() { return new Builder() + .id(this.id) .httpMethod(this.httpMethod) .url(this.url) .headers(this.httpHeaders) @@ -62,6 +73,7 @@ public class HttpRequest { } private HttpRequest(Builder builder) { + this.id = builder.id; this.httpMethod = builder.httpMethod; this.url = builder.url; this.parameters = builder.parameters; @@ -71,6 +83,7 @@ public class HttpRequest { } public static class Builder { + private String id; private HttpMethod httpMethod; private String url; private HttpHeaders headers = new HttpHeaders(); @@ -160,6 +173,17 @@ public class HttpRequest { return this; } + /** + * 请求id + * + * @param id id + * @return Builder + */ + public Builder id(String id) { + this.id = id; + return this; + } + /** * 构建HttpRequest * @@ -169,6 +193,10 @@ public class HttpRequest { requireNonNull(this.httpMethod); requireNonNull(this.url); + if (Strings.isEmpty(this.id)) { + this.id = Nonce.ofNonce(); + } + if (Objects.isNull(this.headers)) { this.headers = new HttpHeaders(); } diff --git a/scfs-api-test/pom.xml b/scfs-api-test/pom.xml index 32836af..ab099aa 100644 --- a/scfs-api-test/pom.xml +++ b/scfs-api-test/pom.xml @@ -33,6 +33,13 @@ spring-boot-maven-plugin 2.7.16 + + org.apache.maven.plugins + maven-surefire-plugin + + true + +