今天在 test 环境部署接口后,群里前端同事说登录页的图形验证码获取失败了。看日志报错信息是:getOutputStream() has already been called for this response. 再看代码,也没看出来代码哪里有问题,之前就是好好的,怎么我部署一下就出问题了。


本地启动调用接口将问题复现后,发现是下午同事提交的代码导致的。同事在项目里加了一个 AOP 来记录所有接口的请求参数,其中记录请求参数的代码如下:

// 接口请求参数
Object[] args = joinPoint.getArgs();
// 报错的代码
extraInfo.put("args", JSONArray.toJSONString(logArgs));

断点查看这个 args 变量的值

default-alt

里面有一个 HeaderWriterResponse 对象,查看这个对象的定义

default-alt

可以发现其实这个参数就是验证码接口中的 HttpServletResponse response 参数:

default-alt

其实不光是 HttpServletResponse 对象会导致序列化报错,HttpServletRequest 也会导致报错,只不过报错信息不一样。解决办法很简单,只需要将这两种类型的参数从 args 中过滤掉即可,本身这两种类型的参数对我们的日志记录也没有任何意义。

// 接口请求参数
Object[] args = joinPoint.getArgs();
List<Object> logArgs = Arrays
                .stream(args)
                .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)))
                .collect(Collectors.toList());
extraInfo.put("args", JSONArray.toJSONString(logArgs));