这是我参与更文挑战的第2天,活动详情查看: 更文挑战
前言
在看日志表的时候,发现请求参数全是空的。就在想肯定是哪里出现问题了,下面就是我的解决问题的一些思路
往期链接
一、问题复现
经过测试,请求下面这个接口可以稳定重现此问题
数据库记录如下所示:
二、解决问题
既然能稳定重现,那么解决问题也就不会太困难了。
相关代码
使用AOP记录日志主要部分的代码如下所示:
切面类
@Component
@Aspect
@Slf4j
public class LogAspect implements Ordered {
// 执行顺序,越小越先执行(遵从同心圆的概念)
private final int order = 100;
@Pointcut("@annotation(cn.jackbin.SimpleRecord.common.anotations.CommonLog)")
public void doHandler(){
}
/**
* 处理请求后执行
*/
@AfterReturning(pointcut = "doHandler()", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
handleLog(joinPoint, null, jsonResult);
}
@AfterThrowing(pointcut = "doHandler()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
handleLog(joinPoint, e, null);
}
/**
* 处理日志
*/
private void handleLog(final JoinPoint joinPoint, final Exception e, final Object jsonResult) {
try {
// 获得自定义注解
CommonLog annotationLog = getAnnotationLog(joinPoint);
if (annotationLog == null)
{
return;
}
// 插入数据操作(已省略)
// 异步保存日志
AsyncManager.me().schedule(AsyncFactory.recordCommonLog(logDO));
} catch (Exception exception) {
log.error("日志记录异常,msg{}", exception.getMessage());
}
}
@Override
public int getOrder() {
return order;
}
}
复制代码
获取请求参数的方法
/**
* 获取请求的参数,放到log中
*
* @param commonLogDO 操作日志
* @throws Exception 异常
*/
private void setRequestValue(CommonLogDO commonLogDO) throws Exception
{
Map<String, String[]> map = ServletUtil.getRequest().getParameterMap();
if (StringUtil.isNotEmpty(map))
{
PropertyPreFilters.MySimplePropertyPreFilter excludefilter = new PropertyPreFilters().addFilter();
excludefilter.addExcludes(EXCLUDE_PROPERTIES);
String params = JSONObject.toJSONString(map, excludefilter);
commonLogDO.setRequestParam(StringUtil.substring(params, 0, 2000));
}
}
复制代码
调试
先看下请求
打断点发现无法获取到Request Payload
经过实际测试才知道,原来request.getParameterMap() 只能获取到 form-data 中的参数
要在在SelectRequest中获取到 Request Payload 需要通过获取请求中的流,再解析出来
解决方案
踩坑
直接使用 req.getInputStream() 这种方式获取到流,在读取流的时候会报
Stream Closed
异常
所以要自己重写一个过滤器,重新将流放进去
实现如下图所示:
实现代码
从流中取数据的逻辑如下所示
// 从流中读取请求数据
ServletInputStream is;
is = req.getInputStream();
int nRead = 1;
int nTotalRead = 0;
byte[] bytes = new byte[10240];
while (nRead > 0) {
nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
if (nRead > 0)
nTotalRead = nTotalRead + nRead;
}
params = new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
复制代码
结果
现在已可以正确记录日志,结果如下图所示:
三、总结
以上代码均可在简账后端中找到
感谢看到最后,非常荣幸能够帮助到你~♥
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END