1. ClientHttpRequestInterceptor 概述
函數(shù)式編程攔截器接口;攔截客戶端HTTP請求寻馏。這個接口的實現(xiàn)可以注冊到RestTemplate中借杰,以修改輸出的ClientHttpRequest和/或傳入的ClientHttpResponse随抠。
攔截器的主要入口點是截取(HttpRequest, byte[]显熏, ClientHttpRequestExecution)揽碘。
2. 實現(xiàn)ClientHttpRequestInterceptor 參數(shù)攔截
logRequestDetails 處理請求參數(shù)
logResponseDetails 處理返回參數(shù)
@Slf4j
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
//打印請求明細
logRequestDetails(request, body);
ClientHttpResponse response = execution.execute(request, body);
//打印響應明細
logResponseDetails(response);
return response;
}
/**
請求參數(shù)
*/
private void logRequestDetails(HttpRequest request, byte[] body) {
log.debug("Headers: {}", request.getHeaders());
log.debug("body: {}", new String(body, Charsets.UTF_8));
log.debug("{}:{}", request.getMethod(), request.getURI());
}
private void logResponseDetails(ClientHttpResponse response) throws IOException {
log.debug("Status code : {}", response.getStatusCode());
log.debug("Status text : {}", response.getStatusText());
log.debug("Headers : {}", response.getHeaders());
log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
}
}
3. 定義日志攔截切面 RequestLogAspect
定義切點openrpc 該切點就是需要攔截請求參數(shù)與返回參數(shù)的地方
@Pointcut("execution(* com.cxist.open.controller.open..*(..))")
public void openrpc() {
}
4. 切點織入邏輯蝉娜;
doAround 方法以舒,捕獲請求參數(shù)
@Around("openrpc()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
調(diào)用異常的時候使用,捕獲異常信息
@AfterThrowing(pointcut = "openrpc()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
5. 具體實現(xiàn)如下霎肯;
@Component
@Aspect
@Slf4j
public class RequestLogAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);
private static Integer SUCCESS = 1;
private static Integer FAIL = 0;
private static String TOKEN = "token";
@Autowired
InterfaceDetailLogService interfaceDetailLogService;
@Autowired
LogClient logClient;
@Resource(name = "openApiThreadExecutor")
ThreadPoolTaskExecutor threadPoolTaskExecutor;
public static void main(String[] args) {
System.out.println("DateUtil.date = " + DateUtil.date());
System.out.println("DateUtil.current = " + DateUtil.current());
System.out.println("DateUtil.currentSeconds = " + DateUtil.currentSeconds());
}
/**
* Controller層都被訪問
*/
@Pointcut("execution(* com.cxist.open.controller.open..*(..))")
public void openrpc() {
}
@Around("openrpc()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Date requestDateTime = DateUtil.date();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Object result = proceedingJoinPoint.proceed();
/**若發(fā)生異常則以下不再執(zhí)行擎颖,可以在doAfterThrow 記錄**/
InterfaceDetailLogDTO logDTO = new InterfaceDetailLogDTO();
logDTO.setIp(request.getRemoteAddr());
logDTO.setUrl(request.getRequestURL().toString());
logDTO.setRequestMethod(request.getMethod());
logDTO.setRespondBody(result.toString());
logDTO.setRequestTime(requestDateTime);
logDTO.setRespondTime(DateUtil.date());
logDTO.setStatus(SUCCESS);
Map<String, Object> paramMap = getRequestParamsByProceedingJoinPoint(proceedingJoinPoint);
logDTO.setRequestBody(JSONUtil.toJsonStr(paramMap));
String token = paramMap.get(TOKEN) != null ? paramMap.get(TOKEN).toString() : "";
MultiValueMap<String, String> headerMap = new LinkedMultiValueMap<>();
headerMap.add(org.apache.http.HttpHeaders.AUTHORIZATION, token);
try {
//從主線程中獲得所有request數(shù)據(jù)
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
threadPoolTaskExecutor.submit(new Runnable() {
@Override
public void run() {
RequestContextHolder.setRequestAttributes(requestAttributes);
log.info("--------------------doAround-------------------------");
Result saveFlag = logClient.save(headerMap, logDTO);
log.info("saveFlag.code ===" + saveFlag.getCode());
}
});
} catch (Exception e) {
log.error("e ===== e" + e);
}
LOGGER.info("Request Info : {}", JSON.toJSONString(logDTO));
return result;
}
@AfterReturning(returning = "ret", pointcut = "openrpc()")
public void doAfterReturning(Object ret) throws Throwable {
// 處理完請求,返回內(nèi)容
log.info("RESPONSE : " + ret);
}
@AfterThrowing(pointcut = "openrpc()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
InterfaceDetailLogDTO logDTO = null;
MultiValueMap<String, String> headerMap = null;
/**異步Feign調(diào)用观游,傳遞request 請求上下文**/
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
logDTO = new InterfaceDetailLogDTO();
logDTO.setIp(request.getRemoteAddr());
logDTO.setUrl(request.getRequestURL().toString());
logDTO.setRequestMethod(request.getMethod());
Map<String, Object> paramsMap = getRequestParamsByJoinPoint(joinPoint);
String token = paramsMap.get(TOKEN) != null ? paramsMap.get(TOKEN).toString() : "";
headerMap = new LinkedMultiValueMap<>();
headerMap.add(org.apache.http.HttpHeaders.AUTHORIZATION, token);
logDTO.setRequestBody(JSONUtil.toJsonStr(paramsMap));
logDTO.setRequestTime(DateUtil.date());
logDTO.setRespondTime(DateUtil.date());
/**異常信息過程搂捧,F(xiàn)eign請求的時候會被拒絕**/
if (e.getMessage().length() > 300) {
logDTO.setErrorMessage(e.getMessage().substring(0, 300));
} else {
logDTO.setErrorMessage(e.getMessage());
}
logDTO.setStatus(FAIL);
InterfaceDetailLogEntity entity = new InterfaceDetailLogEntity();
BeanUtils.copyProperties(logDTO, entity);
try {
InterfaceDetailLogDTO finalLogDTO = logDTO;
MultiValueMap<String, String> finalHeaderMap = headerMap;
//從主線程中獲得所有request數(shù)據(jù)
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
threadPoolTaskExecutor.submit(new Runnable() {
@Override
public void run() {
/**異步Feign調(diào)用,傳遞request 請求上下文**/
RequestContextHolder.setRequestAttributes(requestAttributes);
log.info("------------------doAfterThrow---------------------------");
Result saveFlag = logClient.save(finalHeaderMap, finalLogDTO);
log.info("saveFlag.code ===" + saveFlag.getCode());
}
});
} catch (Exception ex) {
log.error("e ===== ex" + ex);
}
}
private InterfaceDetailLogEntity getInterfaceDetailLogEntity(JoinPoint joinPoint, RuntimeException e, HttpServletRequest request) {
InterfaceDetailLogEntity entity = new InterfaceDetailLogEntity();
entity.setIp(request.getRemoteAddr());
entity.setUrl(request.getRequestURL().toString());
entity.setRequestMethod(request.getMethod());
entity.setRequestBody(JSONUtil.toJsonStr(getRequestParamsByJoinPoint(joinPoint)));
entity.setRequestTime(null);
entity.setRespondTime(DateUtil.date());
entity.setErrorMessage(e.getMessage());
entity.setStatus(FAIL);
return entity;
}
/**
* 獲取入?yún)? *
* @param proceedingJoinPoint
* @return
*/
private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
//參數(shù)名
String[] paramNames = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
//參數(shù)值
Object[] paramValues = proceedingJoinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
//參數(shù)名
String[] paramNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
//參數(shù)值
Object[] paramValues = joinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
Map<String, Object> requestParams = new HashMap<>();
for (int i = 0; i < paramNames.length; i++) {
Object value = paramValues[i];
//如果是文件對象
if (value instanceof MultipartFile) {
MultipartFile file = (MultipartFile) value;
value = file.getOriginalFilename(); //獲取文件名
}
requestParams.put(paramNames[i], value);
}
return requestParams;
}
@Data
public class RequestErrorInfo {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private RuntimeException exception;
}
6 總結(jié)
1.LoggingInterceptor
實現(xiàn) implements ClientHttpRequestInterceptor 封裝請求懂缕,及返回參數(shù)
···
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
//打印請求明細
logRequestDetails(request, body);
ClientHttpResponse response = execution.execute(request, body);
//打印響應明細
logResponseDetails(response);
return response;
}
···
2.RequestLogAspect
定義攔截切面
3. 日志記錄服務類允跑,記錄日志
單獨的日志處理邏輯