springboot 实现
org.springframework.web.util.ContentCachingRequestWrapper 是 spring boot 自带的请求体重复利用的工具,不过他也有缺点
- 内容没有被消费,那么内容就没有被缓存,换句话说你需要先消费请求内容后,才可以正常使用缓存
使用示例
package clown.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Slf4j
public class LogFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
log.info("request0 = {}", new String(requestWrapper.getContentAsByteArray()));
filterChain.doFilter(requestWrapper, response);
log.info("request1 = {}", new String(requestWrapper.getContentAsByteArray()));
}
}
request0无参数打印,request1可以正常打印
自定义实现
package clown.wrapper;
import cn.hutool.core.io.IoUtil;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class CacheHttpRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
private ServletInputStream inputStream;
public CacheHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
// 直接将请求内容读取出来并缓存
body = IoUtil.readBytes(request.getInputStream());
}
// 读取缓存数据
public byte[] getBody() {
return body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (inputStream == null) {
// 返回自定义实现的输入流,并且将缓存的请求内容传递给自定义输入流
inputStream = new CacheHttpInputStream(body);
}
return inputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
class CacheHttpInputStream extends ServletInputStream {
private final ByteArrayInputStream is;
public CacheHttpInputStream(byte[] body) {
this.is = new ByteArrayInputStream(body);
}
@Override
public boolean isFinished() {
return this.isFinished();
}
@Override
public boolean isReady() {
return this.isReady();
}
@Override
public void setReadListener(ReadListener listener) {
this.setReadListener(listener);
}
@Override
public int read() throws IOException {
return is.read();
}
}
}
使用示例
package clown.filter;
import clown.wrapper.CacheHttpRequestWrapper1;
import clown.wrapper.CacheHttpResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Slf4j
public class LogFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CacheHttpRequestWrapper cacheHttpRequestWrapper = new CacheHttpRequestWrapper(request);
log.info("request0 = {}", new String(cacheHttpRequestWrapper.getBody()));
filterChain.doFilter(cacheHttpRequestWrapper, response);
log.info("request1 = {}", new String(cacheHttpRequestWrapper.getBody()));
}
}
request0、request1均可以正常打印