天天看点

Spring Boot aop 获取HttpResponse的状态码

Spring Boot aop 获取HttpResponse的状态码方法如下:

HttpServletResponse httpServletResponse = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
int status = httpServletResponse.getStatus();
           

Spring Boot 项目中,@Around、@AfterReturning、@After注解的Pointcut不能获取到程序异常时返回的HTTPServletResponse的状态码,因为这几个注解执行的条件均是在你调用的接口执行完成之后再执行(不论你的接口调用会不会抛异常)。如果你的接口没问题,正常返回,则上述方法获取到的status为200正常值;如果你的接口抛异常,则该status仍为200,此时时错误的。

原因(个人理解):

当你发送HTTPServletRequest服务器接收到之后,会生成一个HTTPServletResponse对象,这个response对象默认的status初始值为200,如果你的程序内部抛异常了,Java内部会根据你的异常原因给status赋值(比如null空指针异常,status会被赋值为500)。

而使用@Around、@AfterReturning、@After注解时,无论你接口的程序代码是否正常执行,都会被认为该接口调用已经执行完成,你的接口代码出错时会被认为返回一个null,由于调用接口是在你aop代码的@Around或@AfterReturning或@After注解中执行完成的,所以初始化的HTTPServletResponse对象的status值并未做修改(因为你的接口正常调用完成后,Java内部会根据实际情况给status赋值,而上述几个注解加入后,感觉像是跳过了异常(或者说用接口返回的 null处理了异常),status貌似未被赋上错误代码值)。

所以HTTPServletResponse的status值始终为200,即Http的请求与返回总是正常执行完(程序中的异常在aop代码中被捕获到,但未处理)。

最后强调一下:Http请求与返回是否正常执行 与 你的接口代码是否正常执行,这是两个概念。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Aspect
@Component
public class SysLoggerAspect {
    @Autowired
    private LoggerService loggerService;

    @Pointcut("@annotation(com.ytkj.common.annotation.SysLogger)")
    public void loggerPointCut() {

    }

    //@Before为loggerPointCut()执行前,即@SysLogger注解的processRecovery方法执行前。
    //此时获取不到执行后的结果,即状态码、返回结果、运行时间无法获取。故用@Around注解
//    @Before("loggerPointCut()")
//    public void saveSysLog(JoinPoint joinPoint) {
//        PreproRecoveryLog preproRecoveryLog = new PreproRecoveryLog();
//        //请求的参数
//        Object[] args = joinPoint.getArgs();
//        String params="";
//        for(Object o:args){
//            params+=JSON.toJSONString(o);
//        }
//        if(!StringUtils.isEmpty(params)) {
//            preproRecoveryLog.setParams(params);
//        }
//        //设置IP地址
//        preproRecoveryLog.setIp(HttpUtils.getIpAddress());
//        //设置写入日志时间
//        preproRecoveryLog.setCreateDate(new Date());
//
//        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletResponse response = requestAttributes.getResponse();
//        System.out.println(response);
//        System.out.println(response.getStatus());
//
//        //保存系统日志
//        System.out.println("********aop out success*********");
//        loggerService.log(preproRecoveryLog);
//    }

    @Around("loggerPointCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        PreproRecoveryLog preproRecoveryLog = new PreproRecoveryLog();
        //请求的参数
        Object[] args = proceedingJoinPoint.getArgs();
        String params="";
        for(Object o:args){
            params+= JSON.toJSONString(o);
        }
        if(!StringUtils.isEmpty(params)) {
            preproRecoveryLog.setParams(params);
        }
        //设置IP地址
        preproRecoveryLog.setIp(HttpUtils.getIpAddress());
        //设置写入日志时间
        Date createDate = new Date();
        preproRecoveryLog.setCreateDate(createDate);
        long startTime = System.currentTimeMillis();
//        System.out.println("********aop out success1*********");

        Object result = null;
        try {
            //以上为loggerPointCut()执行前,即@SysLogger注解的processRecovery方法执行前
            result = proceedingJoinPoint.proceed();
            //以下为loggerPointCut()执行后,即@SysLogger注解的processRecovery方法执行后

            //获取并设置调用接口运行时长
            long runTime = System.currentTimeMillis() - startTime;
            preproRecoveryLog.setRunTime(runTime);

            //获取并设置HttpRequest对应HttpResponse的状态码
            int status = HttpUtils.getHttpServletResponse().getStatus();
            preproRecoveryLog.setStatusCode(status+"");

            //获取result并转换为JSON字符串  设置写入日志的结果
            String respResult = JSONObject.toJSONString(result);
            preproRecoveryLog.setResult(respResult);
        } catch (Exception e){
            //如果程序执行出错,捕获到异常并记录状态码为-1
//            int status = HttpUtils.getHttpServletResponse().getStatus();
//            System.out.println(status);
            preproRecoveryLog.setStatusCode("-1");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        //保存系统日志
//        System.out.println("********aop out success*********");
        loggerService.log(preproRecoveryLog);
        return result;
    }

}
           

HttpUtils.java

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;


public class HttpUtils {


    /**
     * 尝试获取当前请求的HttpServletRequest实例
     *
     * @return HttpServletRequest
     */
    public static HttpServletRequest getHttpServletRequest() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 尝试获取当前请求的HttpServletResponse实例
     *
     * @return HttpServletResponse
     */
    public static HttpServletResponse getHttpServletResponse() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        } catch (Exception e) {
            return null;
        }
    }

    public static Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }

    /**
     * 获取请求客户端的真实ip地址
     *
     * @param request 请求对象
     * @return ip地址
     */
    public static String getIpAddress(HttpServletRequest request) {

        // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 获取请求客户端的真实ip地址
     *
     * @param
     * @return ip地址
     */
    public static String getIpAddress() {
        // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
        return getIpAddress(getHttpServletRequest());
    }


}

           

附上几个我在查资料时的链接:

https://bbs.csdn.net/topics/391865861?page=1

https://bbs.csdn.net/topics/390675717

https://blog.csdn.net/DuShiWoDeCuo/article/details/78818413

https://blog.csdn.net/puhaiyang/article/details/78146620