fix(log): 修复 LogFilter 无效及无法获取请求、响应体参数的问题

This commit is contained in:
2025-12-30 22:47:54 +08:00
parent 4f8d7725e6
commit 8ce00d8892
8 changed files with 41 additions and 48 deletions

View File

@@ -125,7 +125,7 @@ public class LogAspect {
return false; return false;
} }
// 如果接口匹配排除列表,不记录日志 // 如果接口匹配排除列表,不记录日志
if (logProperties.isMatch(attributes.getRequest().getRequestURI())) { if (logProperties.isMatchExcludeUri(attributes.getRequest().getRequestURI())) {
return false; return false;
} }
return logHandler.isRecord(targetMethod, targetClass); return logHandler.isRecord(targetMethod, targetClass);

View File

@@ -64,7 +64,6 @@ public class LogAutoConfiguration {
* 日志过滤器 * 日志过滤器
*/ */
@Bean @Bean
@ConditionalOnMissingBean
public FilterRegistrationBean<LogFilter> logFilter() { public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>(); FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LogFilter(logProperties)); registrationBean.setFilter(new LogFilter(logProperties));

View File

@@ -51,40 +51,41 @@ public class LogFilter extends OncePerRequestFilter {
protected void doFilterInternal(@NonNull HttpServletRequest request, protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response, @NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException { @NonNull FilterChain filterChain) throws ServletException, IOException {
if (!this.isFilter(request)) { if (this.isNotFilter(request)) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return;
} }
// 包装可重复读取请求及响应 // 包装可重复读取请求及响应
boolean isExcludeUri = logProperties.isMatch(request.getRequestURI()); RepeatReadRequestWrapper wrappedRequest = request instanceof RepeatReadRequestWrapper wrapped
HttpServletRequest requestWrapper = (isExcludeUri || !this.isRequestWrapper(request)) ? wrapped
? request
: new RepeatReadRequestWrapper(request); : new RepeatReadRequestWrapper(request);
HttpServletResponse responseWrapper = (isExcludeUri || !this.isResponseWrapper(response)) RepeatReadResponseWrapper wrappedResponse = response instanceof RepeatReadResponseWrapper wrapped
? response ? wrapped
: new RepeatReadResponseWrapper(response); : new RepeatReadResponseWrapper(response);
filterChain.doFilter(requestWrapper, responseWrapper); filterChain.doFilter(wrappedRequest, wrappedResponse);
// 如果响应被包装了,复制缓存数据到原始响应 // 复制缓存数据到原始响应
if (responseWrapper instanceof RepeatReadResponseWrapper wrappedResponse) { wrappedResponse.copyBodyToResponse();
wrappedResponse.copyBodyToResponse();
}
} }
/** /**
* 是否过滤请求 * 是否过滤
* *
* @param request 请求对象 * @param request 请求对象
* @return 是否过滤请求 * @return true: 不过滤; false: 过滤
*/ */
private boolean isFilter(HttpServletRequest request) { private boolean isNotFilter(HttpServletRequest request) {
if (!isRequestValid(request)) { if (!isRequestValid(request)) {
return false; return true;
} }
// 不拦截 /error // 不拦截 /error
ServerProperties serverProperties = SpringUtil.getBean(ServerProperties.class); ServerProperties serverProperties = SpringUtil.getBean(ServerProperties.class);
return !request.getRequestURI().equals(serverProperties.getError().getPath()); if (request.getRequestURI().equals(serverProperties.getError().getPath())) {
return true;
}
// 放行路径
return logProperties.isMatchExcludeUri(request.getRequestURI());
} }
/** /**
@@ -101,24 +102,4 @@ public class LogFilter extends OncePerRequestFilter {
return false; return false;
} }
} }
/**
* 是否需要包装输入流
*
* @param request 请求对象
* @return truefalse
*/
private boolean isRequestWrapper(HttpServletRequest request) {
return !(request instanceof RepeatReadRequestWrapper);
}
/**
* 是否需要包装输出流
*
* @param response 响应对象
* @return truefalse
*/
private boolean isResponseWrapper(HttpServletResponse response) {
return !(response instanceof RepeatReadResponseWrapper);
}
} }

View File

@@ -21,6 +21,7 @@ import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.wrapper.RepeatReadRequestWrapper; import top.continew.starter.core.wrapper.RepeatReadRequestWrapper;
import top.continew.starter.log.http.RecordableHttpRequest; import top.continew.starter.log.http.RecordableHttpRequest;
@@ -79,11 +80,17 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
@Override @Override
public String getBody() { public String getBody() {
if (request instanceof RepeatReadRequestWrapper wrapper && !wrapper.isMultipartContent(request)) { try {
String body = JakartaServletUtil.getBody(request); RepeatReadRequestWrapper wrappedRequest = WebUtils
.getNativeRequest(request, RepeatReadRequestWrapper.class);
if (wrappedRequest == null || wrappedRequest.isMultipartContent(request)) {
return null;
}
String body = wrappedRequest.getContentAsString();
return JSONUtil.isTypeJSON(body) ? body : null; return JSONUtil.isTypeJSON(body) ? body : null;
} catch (Exception e) {
return null;
} }
return null;
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package top.continew.starter.log.http.servlet;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.util.WebUtils;
import top.continew.starter.core.util.ServletUtils; import top.continew.starter.core.util.ServletUtils;
import top.continew.starter.core.wrapper.RepeatReadResponseWrapper; import top.continew.starter.core.wrapper.RepeatReadResponseWrapper;
import top.continew.starter.log.http.RecordableHttpResponse; import top.continew.starter.log.http.RecordableHttpResponse;
@@ -54,11 +55,17 @@ public final class RecordableServletHttpResponse implements RecordableHttpRespon
@Override @Override
public String getBody() { public String getBody() {
if (response instanceof RepeatReadResponseWrapper wrapper && !wrapper.isStreamingResponse()) { try {
String body = wrapper.getResponseContent(); RepeatReadResponseWrapper wrappedResponse = WebUtils
.getNativeResponse(response, RepeatReadResponseWrapper.class);
if (wrappedResponse == null || wrappedResponse.isStreamingResponse()) {
return null;
}
String body = wrappedResponse.getResponseContent();
return JSONUtil.isTypeJSON(body) ? body : null; return JSONUtil.isTypeJSON(body) ? body : null;
} catch (Exception e) {
return null;
} }
return null;
} }
@Override @Override

View File

@@ -92,9 +92,9 @@ public class LogProperties {
* 是否匹配放行路由 * 是否匹配放行路由
* *
* @param uri 请求 URI * @param uri 请求 URI
* @return 是否匹配 * @return true: 匹配; false: 不匹配
*/ */
public boolean isMatch(String uri) { public boolean isMatchExcludeUri(String uri) {
return this.getExcludePatterns().stream().anyMatch(pattern -> SpringWebUtils.isMatch(uri, pattern)); return this.getExcludePatterns().stream().anyMatch(pattern -> SpringWebUtils.isMatch(uri, pattern));
} }
} }

View File

@@ -96,7 +96,7 @@ public class AccessLogUtils {
*/ */
public static boolean exclusionPath(LogProperties properties, String path) { public static boolean exclusionPath(LogProperties properties, String path) {
// 放行路由配置的排除检查 // 放行路由配置的排除检查
return properties.isMatch(path) || RESOURCE_PATH.stream() return properties.isMatchExcludeUri(path) || RESOURCE_PATH.stream()
.anyMatch(resourcePath -> SpringWebUtils.isMatchAnt(path, resourcePath)); .anyMatch(resourcePath -> SpringWebUtils.isMatchAnt(path, resourcePath));
} }

View File

@@ -70,7 +70,6 @@ public class LogAutoConfiguration implements WebMvcConfigurer {
* 日志过滤器 * 日志过滤器
*/ */
@Bean @Bean
@ConditionalOnMissingBean
public FilterRegistrationBean<LogFilter> logFilter() { public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>(); FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LogFilter(logProperties)); registrationBean.setFilter(new LogFilter(logProperties));