mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-13 14:09:00 +08:00
fix log multipart serialization
This commit is contained in:
1 parent
2bc5fb5f24
commit
0a15577761
2 files changed
+124
-6
No files matched your search
+27
-6
@@ -24,15 +24,25 @@ import com.pig4cloud.pigx.common.core.jackson.PigxJavaTimeModule;
|
||||
import com.pig4cloud.pigx.common.log.config.PigxLogProperties;
|
||||
import com.pig4cloud.pigx.common.log.util.JacksonSensitiveFieldUtil;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.Part;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -47,11 +57,9 @@ public class SysLogListener implements InitializingBean {
|
||||
/**
|
||||
* 忽略序列化的对象类型
|
||||
*/
|
||||
private final static Class[] ignoreClass = {ServletRequest.class, BindingResult.class};
|
||||
|
||||
/**
|
||||
* new 一个 避免日志脱敏策略影响全局ObjectMapper
|
||||
*/
|
||||
private static final Class<?>[] IGNORE_CLASSES = {ServletRequest.class, ServletResponse.class, BindingResult.class,
|
||||
MultipartFile.class, Part.class, InputStream.class, OutputStream.class, Reader.class, Writer.class,
|
||||
Resource.class, File.class, Path.class};
|
||||
|
||||
private final RemoteLogService remoteLogService;
|
||||
|
||||
@@ -69,7 +77,7 @@ public class SysLogListener implements InitializingBean {
|
||||
Object[] args = (Object[]) source.getBody();
|
||||
List<Object> list = CollUtil.toList(args);
|
||||
// 删除部分无法序列化的参数
|
||||
list.removeIf(obj -> Arrays.stream(ignoreClass).anyMatch(clazz -> clazz.isAssignableFrom(obj.getClass())));
|
||||
list.removeIf(this::isIgnoredParameter);
|
||||
|
||||
try {
|
||||
// 序列化参数
|
||||
@@ -84,6 +92,19 @@ public class SysLogListener implements InitializingBean {
|
||||
remoteLogService.saveLog(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断请求参数是否属于不可异步序列化的类型
|
||||
* <p>
|
||||
* 请求结束后 Tomcat 会清理 multipart 临时文件,流、文件类参数在异步线程中序列化会触发
|
||||
* NoSuchFileException,需要在序列化前剔除。
|
||||
* @param obj 请求参数,可能为 null(null 可正常序列化,予以保留)
|
||||
* @return true 表示需要从序列化列表中剔除
|
||||
*/
|
||||
private boolean isIgnoredParameter(Object obj) {
|
||||
return Objects.nonNull(obj)
|
||||
&& Arrays.stream(IGNORE_CLASSES).anyMatch(clazz -> clazz.isAssignableFrom(obj.getClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
String[] ignorableFieldNames = logProperties.getExcludeFields().toArray(new String[0]);
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.pig4cloud.pigx.common.log.event;
|
||||
|
||||
import com.pig4cloud.pigx.admin.api.dto.SysLogDTO;
|
||||
import com.pig4cloud.pigx.admin.api.feign.RemoteLogService;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.log.config.PigxLogProperties;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link SysLogListener} 请求参数过滤测试
|
||||
*
|
||||
* @author lengleng
|
||||
*/
|
||||
class SysLogListenerTests {
|
||||
|
||||
/**
|
||||
* MultipartFile 参数必须在序列化前被剔除,且日志仍正常保存
|
||||
*/
|
||||
@Test
|
||||
void filtersMultipartFileBeforeSerializingRequestParams() {
|
||||
RemoteLogService remoteLogService = mock(RemoteLogService.class);
|
||||
when(remoteLogService.saveLog(any(SysLogDTO.class))).thenReturn(R.ok(Boolean.TRUE));
|
||||
|
||||
PigxLogProperties logProperties = new PigxLogProperties();
|
||||
logProperties.setExcludeFields(List.of());
|
||||
SysLogListener listener = new SysLogListener(remoteLogService, logProperties);
|
||||
listener.afterPropertiesSet();
|
||||
|
||||
SysLogDTO sysLog = new SysLogDTO();
|
||||
sysLog.setBody(new Object[] { new ThrowingMultipartFile() });
|
||||
|
||||
listener.saveSysLog(new SysLogEvent(sysLog));
|
||||
|
||||
ArgumentCaptor<SysLogDTO> captor = ArgumentCaptor.forClass(SysLogDTO.class);
|
||||
verify(remoteLogService).saveLog(captor.capture());
|
||||
assertThat(captor.getValue().getParams()).isEqualTo("[]");
|
||||
assertThat(captor.getValue().getBody()).isNull();
|
||||
}
|
||||
|
||||
private static class ThrowingMultipartFile implements MultipartFile {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalFilename() {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferTo(File dest) throws IOException, IllegalStateException {
|
||||
throw new AssertionError("MultipartFile should be filtered before serialization");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user