package com.vincent.rsf.server.api.feign;
|
|
import com.vincent.rsf.httpaudit.model.HttpAuditDecision;
|
import com.vincent.rsf.httpaudit.service.HttpAuditOutboundRecorder;
|
import feign.Client;
|
import feign.Request;
|
import feign.Response;
|
import feign.Util;
|
import lombok.RequiredArgsConstructor;
|
|
import java.io.IOException;
|
import java.nio.charset.StandardCharsets;
|
|
/**
|
* Feign 出站写 sys_http_audit_log(与 RestTemplate 共用规则与截断)
|
*/
|
@RequiredArgsConstructor
|
public class AuditingFeignClient implements Client {
|
|
private static final String FN_FEIGN = "HTTP出站(Feign)";
|
|
private final Client delegate;
|
private final HttpAuditOutboundRecorder outboundRecorder;
|
|
@Override
|
public Response execute(Request request, Request.Options options) throws IOException {
|
if (!outboundRecorder.isAuditEnabled()) {
|
return delegate.execute(request, options);
|
}
|
String url = request.url();
|
String method = request.httpMethod().name();
|
byte[] reqBytes = request.body() == null ? new byte[0] : request.body();
|
String reqText = new String(reqBytes, StandardCharsets.UTF_8);
|
HttpAuditDecision dec = outboundRecorder.decideOutbound(url, method, reqText);
|
long t0 = System.currentTimeMillis();
|
Response resp;
|
try {
|
resp = delegate.execute(request, options);
|
} catch (Throwable t) {
|
outboundRecorder.saveOutbound(FN_FEIGN, url, method, reqText, dec, null, null, t0, t);
|
if (t instanceof IOException) {
|
throw (IOException) t;
|
}
|
if (t instanceof RuntimeException) {
|
throw (RuntimeException) t;
|
}
|
if (t instanceof Error) {
|
throw (Error) t;
|
}
|
throw new IOException(t);
|
}
|
if (!dec.isAudit()) {
|
return resp;
|
}
|
byte[] respBytes;
|
try {
|
respBytes = Util.toByteArray(resp.body().asInputStream());
|
} catch (IOException e) {
|
outboundRecorder.saveOutbound(FN_FEIGN, url, method, reqText, dec, resp.status(), null, t0, e);
|
throw e;
|
}
|
String resText = new String(respBytes, StandardCharsets.UTF_8);
|
outboundRecorder.saveOutbound(FN_FEIGN, url, method, reqText, dec, resp.status(), resText, t0, null);
|
return Response.builder()
|
.status(resp.status())
|
.reason(resp.reason())
|
.headers(resp.headers())
|
.body(respBytes)
|
.request(resp.request())
|
.build();
|
}
|
}
|