package com.vincent.rsf.httpaudit.service; import com.vincent.rsf.httpaudit.entity.HttpAuditLog; import com.vincent.rsf.httpaudit.model.HttpAuditDecision; import com.vincent.rsf.httpaudit.props.HttpAuditProperties; import com.vincent.rsf.httpaudit.support.HttpAuditSupport; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; import java.util.Date; /** * 出站 HTTP 审计落库(RestTemplate / Feign 共用) */ @Slf4j @RequiredArgsConstructor public class HttpAuditOutboundRecorder { private final HttpAuditAsyncRecorder recorder; private final HttpAuditProperties props; private final Environment environment; private final HttpAuditRuleService ruleService; public boolean isAuditEnabled() { return props.isEnabled(); } public HttpAuditDecision decideOutbound(String url, String method, String requestBody) { return ruleService.decideOutbound(url, method, requestBody == null ? "" : requestBody); } public void saveOutbound(String functionDesc, String url, String method, String reqText, HttpAuditDecision dec, Integer httpStatus, String resText, long startTimeMs, Throwable ex) { if (!dec.isAudit()) { return; } try { int reqMax = dec.getRequestMaxChars() != null ? dec.getRequestMaxChars() : props.getDefaultRequestStoreChars(); int resMax = dec.getResponseMaxChars() != null ? dec.getResponseMaxChars() : props.getMaxResponseStoreChars(); String reqStored = HttpAuditSupport.storeWithCharLimit(reqText, reqMax); String resStored = HttpAuditSupport.storeWithCharLimit(resText, resMax); int truncated = HttpAuditSupport.overCharLimit(resText, resMax) ? 1 : 0; int ok = (ex == null && httpStatus != null && httpStatus >= 200 && httpStatus < 400) ? 1 : 0; String errMsg = null; if (ex != null) { String s = ex.toString(); errMsg = s.length() > 4000 ? s.substring(0, 4000) + "..." : s; } String appName = environment.getProperty("spring.application.name", "unknown"); String uriStored = HttpAuditSupport.truncateUriForStore(url, 512); HttpAuditLog entity = new HttpAuditLog() .setServiceName(appName) .setScopeType("EXTERNAL") .setUri(uriStored) .setIoDirection("OUT") .setMethod(method) .setFunctionDesc(functionDesc) .setQueryString(null) .setRequestBody(reqStored) .setResponseBody(resStored) .setResponseTruncated(truncated) .setHttpStatus(httpStatus) .setOkFlag(ok) .setSpendMs((int) Math.min(Integer.MAX_VALUE, System.currentTimeMillis() - startTimeMs)) .setClientIp(null) .setErrorMessage(errMsg) .setCreateTime(new Date()) .setDeleted(0); recorder.save(entity); } catch (Throwable t) { log.debug("http-audit 出站组装审计失败:{}", t.getMessage()); } } }