AOP拦截日志报错llegalStateException: It is illegal to call this method if the current request is not in asynchronous mode
原文链接:https://my.oschina.net/mengzhang6/blog/2395893
关于一次AOP拦截入参记录日志报错的梳理总结
将服务发布到tomcat中后,观察服务的运行状态以及日志记录状况; 发现有如下一个问题:
2018-10-31 16:20:10,701 [] INFO aspect.PayMethodLogAspectJ - rest 请求开始{1540974010700}:clazzName: com.yuantu.unified.pay.openapi.OpenApiRest, methodName:preOrder, 参数:[Ljava.lang.Object;@49ffa5bd
2018-10-31 16:20:10,790 [] INFO aspect.PayMethodLogAspectJ - rest 返回结束{1540974010700}::clazzName: com.yuantu.unified.pay.openapi.OpenApiRest, methodName:preOrder, 结果:{"msg":"subCorpNo{3701011318}","resultCode":"101","startTime":1540974010785,"success":false,"timeConsum":0},耗时毫秒数 89
日志中记录入参并没有详细的记录下来,而是记录了一个Object,这样的日志在将来的查询问题的时候是不可用的,遂进行检查代码查找问题;
代码如下:
@Around("within(com.yuantu.unified.pay.openapi..*) || within(com.yuantu.unified.pay.rest..*)") public Object setCorporation(ProceedingJoinPoint joinPoint) throws Throwable { String classType = joinPoint.getTarget().getClass().getName(); Class<?> clazz = Class.forName(classType); String clazzName = clazz.getName(); String methodName = joinPoint.getSignature().getName(); Long logId = System.currentTimeMillis(); Object[] args = joinPoint.getArgs(); String paramter = ""; if (args != null) { try { paramter = JSON.toJSONString(args); } catch (Exception e) { paramter = args.toString(); } } Long currentTime = System.currentTimeMillis(); logger.info("rest 请求开始{" + logId + "}:clazzName: " + clazzName + ", methodName:" + methodName + ", 参数:" + paramter); Object proceed = Result.createFailResult(); try { proceed = joinPoint.proceed(args); } catch (Exception e) { proceed = Result.createFailResult("系统异常,请及时与我们联系,以便及时解决。错误类型:" + e.getClass().getName() +" 错误信息:"+ e.getMessage()); logger.error("rest 请求发生异常{" + logId + "}:clazzName: " + clazzName + ", methodName:" + methodName + ", 参数:" + paramter, e); } String result = ""; if (proceed != null) { result = JSON.toJSONString(proceed); } Long timeDiff = System.currentTimeMillis() - currentTime; logger.info("rest 返回结束{" + logId + "}::clazzName: " + clazzName + ", methodName:" + methodName + ", 结果:" + result + ",耗时毫秒数 " + timeDiff); return proceed; }
最初的观察并没有发现明显的问题,因为paramter本身就是String类型; 后进行debug后,定位出问题所在位置: paramter = JSON.toJSONString(args); 在执行后报错:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
上网查询资料后发现,是因为使用 Object[] args = joinPoint.getArgs(); 获取入参的时候,args还包含了一些其他的内容,比如ServletRequest等,而这些入参并不能进行序列化,所以JSON.toJSONString时报错;
改造后的方法为:
Object[] args = joinPoint.getArgs(); Object[] arguments = new Object[args.length]; for (int i = 0; i < args.length; i++) { if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) { //ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) //ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response continue; } arguments[i] = args[i]; } String paramter = ""; if (arguments != null) { try { paramter = JSONObject.toJSONString(arguments); } catch (Exception e) { paramter = arguments.toString(); } } logger.info("rest 请求开始{" + logId + "}:clazzName: " + clazzName + ", methodName:" + methodName + ", 参数:" + paramter);
将不能进行序列化的入参过滤掉,只要留下我们需要记录的入参参数记录到日志中即可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
2018-04-13 mysql DISTINCT根据某字段去重同时查出其他字段