1. ClientHttpRequestInterceptor 概述
函数式编程拦截器接口;拦截客户端HTTP请求。这个接口的实现可以注册到RestTemplate中,以修改输出的ClientHttpRequest和/或传入的ClientHttpResponse。
拦截器的主要入口点是截取(HttpRequest, byte[], ClientHttpRequestExecution)。
2. 实现ClientHttpRequestInterceptor 参数拦截
logRequestDetails 处理请求参数
logResponseDetails 处理返回参数
@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;
}
/**
请求参数
*/
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 该切点就是需要拦截请求参数与返回参数的地方
@Pointcut("execution(* com.cxist.open.controller.open..*(..))")
public void openrpc() {
}
4. 切点织入逻辑;
doAround 方法,捕获请求参数
@Around("openrpc()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
调用异常的时候使用,捕获异常信息
@AfterThrowing(pointcut = "openrpc()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
5. 具体实现如下;
@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();
/**若发生异常则以下不再执行,可以在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数据
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 {
// 处理完请求,返回内容
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调用,传递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());
/**异常信息过程,Feign请求的时候会被拒绝**/
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数据
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
threadPoolTaskExecutor.submit(new Runnable() {
@Override
public void run() {
/**异步Feign调用,传递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;
}
/**
* 获取入参
*
* @param proceedingJoinPoint
* @return
*/
private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
//参数名
String[] paramNames = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
//参数值
Object[] paramValues = proceedingJoinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
//参数名
String[] paramNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
//参数值
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 总结
1.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;
}
···
2.RequestLogAspect
定义拦截切面
3. 日志记录服务类,记录日志
单独的日志处理逻辑








网友评论