request id

main
13009 2024-03-26 11:07:55 +08:00
parent 04ec5ee891
commit 92beab28c1
7 changed files with 69 additions and 27 deletions

View File

@ -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.HttpRequest;
import com.czcb.scfs.api.core.http.OriginalResponse; import com.czcb.scfs.api.core.http.OriginalResponse;
import com.czcb.scfs.api.core.util.DateTimes; 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 com.czcb.scfs.api.core.util.Strings;
import java.util.Map; import java.util.Map;
@ -33,7 +32,7 @@ public class DefaultCredential implements Credential {
} }
private void addNecessityCustomizeHeaders(HttpRequest request) { private void addNecessityCustomizeHeaders(HttpRequest request) {
request.getHttpHeaders().addHeader(NONCE, Nonce.ofNonce()); request.getHttpHeaders().addHeader(NONCE, request.getId());
request.getHttpHeaders().addHeader(TIMESTAMP, DateTimes.ofTimestamp()); request.getHttpHeaders().addHeader(TIMESTAMP, DateTimes.ofTimestamp());
} }

View File

@ -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.TimestampException;
import com.czcb.scfs.api.core.exception.ValidationException; import com.czcb.scfs.api.core.exception.ValidationException;
import com.czcb.scfs.api.core.http.HttpLogger; 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.http.OriginalResponse;
import com.czcb.scfs.api.core.util.Strings; 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; return httpCode < HTTP_OK || httpCode >= HTTP_MULT_CHOICE;
} }
private void validateTimestamp(OriginalResponse response) { private void validateTimestamp(HttpRequest request, OriginalResponse response) {
try { try {
String timestamp = response.getHttpHeaders().getHeader(TIMESTAMP); String timestamp = response.getHttpHeaders().getHeader(TIMESTAMP);
if (Strings.isEmpty(timestamp)) { if (Strings.isEmpty(timestamp)) {
@ -51,19 +52,19 @@ public final class DefaultValidator implements Validator {
timestamp, response.getHttpHeaders().getHeader(REQUEST_ID))); timestamp, response.getHttpHeaders().getHeader(REQUEST_ID)));
} }
} catch (Exception e) { } catch (Exception e) {
httpLogger.logResponseError(response); httpLogger.logResponseError(request, response);
throw new TimestampException(e.getMessage(), e); throw new TimestampException(e.getMessage(), e);
} }
} }
@Override @Override
public void validate(OriginalResponse response, Channel channel) { public void validate(HttpRequest request, OriginalResponse response, Channel channel) {
if (isInvalidHttpCode(response.getStatusCode())) { if (isInvalidHttpCode(response.getStatusCode())) {
httpLogger.logHttpStatus(response); httpLogger.logHttpStatus(response);
} }
// 校验时间戳 // 校验时间戳
validateTimestamp(response); validateTimestamp(request, response);
// 请求头包含 SecretKey 进行验签 // 请求头包含 SecretKey 进行验签
if (!headerContainsSecretKey(response)) { if (!headerContainsSecretKey(response)) {
@ -80,7 +81,7 @@ public final class DefaultValidator implements Validator {
} }
if (!verifier.verify(null, message, signature)) { if (!verifier.verify(null, message, signature)) {
httpLogger.logResponseError(response); httpLogger.logResponseError(request, response);
throw new ValidationException(String.format("响应校验失败, 签名校验未通过, Request-Id=%s", throw new ValidationException(String.format("响应校验失败, 签名校验未通过, Request-Id=%s",
response.getHttpHeaders().getHeader(REQUEST_ID))); response.getHttpHeaders().getHeader(REQUEST_ID)));
} }

View File

@ -1,6 +1,7 @@
package com.czcb.scfs.api.core.cipher; package com.czcb.scfs.api.core.cipher;
import com.czcb.scfs.api.core.Channel; import com.czcb.scfs.api.core.Channel;
import com.czcb.scfs.api.core.http.HttpRequest;
import com.czcb.scfs.api.core.http.OriginalResponse; 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);
} }

View File

@ -68,18 +68,19 @@ public abstract class AbstractApiClient implements ApiClient {
// 实际调用 // 实际调用
originalResponse = doRemoteExecute(newRequest); originalResponse = doRemoteExecute(newRequest);
} catch (Exception e) { } catch (Exception e) {
httpLogger.logRemoteError(newRequest, e.getMessage());
throw new ApiClientException(e); throw new ApiClientException(e);
} finally { } finally {
watch.stop(); watch.stop();
} }
// 校验响应 // 校验响应
OriginalResponse resultfulResponse = validateResponse(originalResponse); OriginalResponse resultfulResponse = validateResponse(newRequest, originalResponse);
// 解析返回数据 // 解析返回数据
HttpResponse<T> httpResponse = assembleHttpResponse(resultfulResponse, responseClass); HttpResponse<T> httpResponse = assembleHttpResponse(resultfulResponse, responseClass);
// 打印响应结果 // 打印响应结果
httpLogger.logResponse(originalResponse, httpResponse, watch.getLastTaskTimeMillis()); httpLogger.logResponse(newRequest, originalResponse, httpResponse, watch.getLastTaskTimeMillis());
return httpResponse; return httpResponse;
} }
@ -94,6 +95,7 @@ public abstract class AbstractApiClient implements ApiClient {
request = httpRequestEncrypt(request); request = httpRequestEncrypt(request);
// 组合请求数据 // 组合请求数据
HttpRequest.Builder builder = new HttpRequest.Builder() HttpRequest.Builder builder = new HttpRequest.Builder()
.id(request.getId())
.url(fullUrlPattern(request)) .url(fullUrlPattern(request))
.httpMethod(request.getHttpMethod()) .httpMethod(request.getHttpMethod())
.addHeader(AUTHORIZATION, getAuthorization(request)) .addHeader(AUTHORIZATION, getAuthorization(request))
@ -172,8 +174,8 @@ public abstract class AbstractApiClient implements ApiClient {
* @param originalResponse OriginalResponse * @param originalResponse OriginalResponse
* @return OriginalResponse * @return OriginalResponse
*/ */
private OriginalResponse validateResponse(OriginalResponse originalResponse) { private OriginalResponse validateResponse(HttpRequest request, OriginalResponse originalResponse) {
validator.validate(originalResponse, getProfile().getChannel()); validator.validate(request, originalResponse, getProfile().getChannel());
return originalResponse; return originalResponse;
} }

View File

@ -28,19 +28,19 @@ public class HttpLogger {
return; return;
} }
logger.info("请求行:{} {} {}", request.getHttpMethod(), request.getUrl(), httpVersion); logger.info("[{}] 请求行:{} {} {}", request.getId(), request.getHttpMethod(), request.getUrl(), httpVersion);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
request.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); 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) { if (request.getRequestBody() instanceof EncryptRequestBody) {
EncryptRequestBody body = (EncryptRequestBody) request.getRequestBody(); EncryptRequestBody body = (EncryptRequestBody) request.getRequestBody();
logger.info("请求原始报文:{}", Strings.toStr(body.getOriginalBody())); logger.info("[{}] 请求原始报文:{}", request.getId(), Strings.toStr(body.getOriginalBody()));
logger.info("请求加密报文:{}", Strings.toStr(body.getBody())); logger.info("[{}] 请求加密报文:{}", request.getId(), Strings.toStr(body.getBody()));
} else if (request.getRequestBody() instanceof JsonRequestBody) { } else if (request.getRequestBody() instanceof JsonRequestBody) {
JsonRequestBody body = (JsonRequestBody) request.getRequestBody(); 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 duration
* @param <T> * @param <T>
*/ */
protected <T> void logResponse(OriginalResponse originalResponse, HttpResponse<T> response, long duration) { protected <T> void logResponse(HttpRequest request, OriginalResponse originalResponse, HttpResponse<T> response, long duration) {
if (!logEnabled) { if (!logEnabled) {
return; return;
} }
logger.info("响应行:{} {}", originalResponse.getVersion(), originalResponse.getStatusCode()); logger.info("[{}] 响应行:{} {}", request.getId(), originalResponse.getVersion(), originalResponse.getStatusCode());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
response.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); response.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(), ";"));
logger.info("响应原始报文:{}", Strings.toStr(response.getOriginalBody())); logger.info("[{}] 响应原始报文:{}", request.getId(), Strings.toStr(response.getOriginalBody()));
logger.info("响应解密报文:{}", Json.toJson(response.getServiceResponse())); 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 * @param originalResponse
*/ */
public void logResponseError(OriginalResponse originalResponse) { public void logResponseError(HttpRequest request, OriginalResponse originalResponse) {
logger.info("响应:{} {}", originalResponse.getVersion(), originalResponse.getStatusCode()); logger.error("[{}] 响应:{} {}", request.getId(), originalResponse.getVersion(), originalResponse.getStatusCode());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
originalResponse.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";")); originalResponse.getHttpHeaders().getHeaders().forEach((k, v) -> sb.append(k).append("=").append(v).append(";"));
logger.info("响应头:{}", Strings.removeSuffix(sb.toString(), ";")); logger.error("[{}] 响应头:{}", request.getId(), Strings.removeSuffix(sb.toString(), ";"));
logger.info("响应原始报文:{}", Strings.toStr((originalResponse.getBody()))); logger.error("[{}] 响应原始报文:{}", request.getId(), Strings.toStr((originalResponse.getBody())));
} }
public void logHttpStatus(OriginalResponse response) { public void logHttpStatus(OriginalResponse response) {
// TODO 打印状态码说明 // TODO 打印状态码说明
} }
public void logRemoteError(HttpRequest newRequest, String message) {
logger.error("[{}] 远程调用异常:{}", newRequest.getId(), message);
}
} }

View File

@ -1,5 +1,8 @@
package com.czcb.scfs.api.core.http; 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.Map;
import java.util.Objects; import java.util.Objects;
@ -14,6 +17,9 @@ import static java.util.Objects.requireNonNull;
* @since 2.0.0 * @since 2.0.0
*/ */
public class HttpRequest { public class HttpRequest {
// 请求Id
private final String id;
// http 请求方法 // http 请求方法
private final HttpMethod httpMethod; private final HttpMethod httpMethod;
// 地址 // 地址
@ -27,6 +33,10 @@ public class HttpRequest {
// 是否开启压缩 // 是否开启压缩
private final boolean compression; private final boolean compression;
public String getId() {
return id;
}
public HttpMethod getHttpMethod() { public HttpMethod getHttpMethod() {
return httpMethod; return httpMethod;
} }
@ -53,6 +63,7 @@ public class HttpRequest {
public Builder newBuilder() { public Builder newBuilder() {
return new Builder() return new Builder()
.id(this.id)
.httpMethod(this.httpMethod) .httpMethod(this.httpMethod)
.url(this.url) .url(this.url)
.headers(this.httpHeaders) .headers(this.httpHeaders)
@ -62,6 +73,7 @@ public class HttpRequest {
} }
private HttpRequest(Builder builder) { private HttpRequest(Builder builder) {
this.id = builder.id;
this.httpMethod = builder.httpMethod; this.httpMethod = builder.httpMethod;
this.url = builder.url; this.url = builder.url;
this.parameters = builder.parameters; this.parameters = builder.parameters;
@ -71,6 +83,7 @@ public class HttpRequest {
} }
public static class Builder { public static class Builder {
private String id;
private HttpMethod httpMethod; private HttpMethod httpMethod;
private String url; private String url;
private HttpHeaders headers = new HttpHeaders(); private HttpHeaders headers = new HttpHeaders();
@ -160,6 +173,17 @@ public class HttpRequest {
return this; return this;
} }
/**
* id
*
* @param id id
* @return Builder
*/
public Builder id(String id) {
this.id = id;
return this;
}
/** /**
* HttpRequest * HttpRequest
* *
@ -169,6 +193,10 @@ public class HttpRequest {
requireNonNull(this.httpMethod); requireNonNull(this.httpMethod);
requireNonNull(this.url); requireNonNull(this.url);
if (Strings.isEmpty(this.id)) {
this.id = Nonce.ofNonce();
}
if (Objects.isNull(this.headers)) { if (Objects.isNull(this.headers)) {
this.headers = new HttpHeaders(); this.headers = new HttpHeaders();
} }

View File

@ -33,6 +33,13 @@
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.16</version> <version>2.7.16</version>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>