SpringCloud

2022-12-30 ClientHttpRequestInte

2022-12-29  本文已影响0人  ForestPei

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. 日志记录服务类,记录日志

单独的日志处理逻辑

上一篇 下一篇

猜你喜欢

热点阅读