解决流只能读一次的问题,getInputStream() has already been called for this request
程序员文章站
2024-02-02 18:35:28
...
场景:在aop的日志中想获取 post请求的json数据时报错,因为在后台 控制器的接口中流已经读取了,导致日志这里获取就会报错,需要重写请求的 getInputStream getReader,然后配置一个过滤器
1、requestWrapper
public class StreamWrapper extends HttpServletRequestWrapper{
public String _body;
public StreamWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuffer sBuffer = new StringBuffer();
BufferedReader bufferedReader = request.getReader();
String line;
while ((line = bufferedReader.readLine()) != null) {
sBuffer.append(line);
}
_body = sBuffer.toString();
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
return new ServletInputStream() {
@Override
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
2、定义一个过滤器
public class StreamFilter implements Filter {
private final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList("/api/file/upload")));
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest) {
HttpServletRequest servletRequest = (HttpServletRequest) request;
String requestURI = servletRequest.getRequestURI();
if (ALLOWED_PATHS.contains(requestURI)){
chain.doFilter(servletRequest,response);
}else {
requestWrapper = new StreamWrapper(servletRequest);
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
// 在chain.doFiler方法中传递新的request对象
chain.doFilter(requestWrapper, response);
}
}
}
@Override
public void destroy() {
}
}
3、springboot配置过滤器
@Configuration
public class StreamConfig {
@Value("${stream.enabled}")
private String enabled;
@Value("${stream.excludes}")
private String excludes;
@Value("${stream.urlPatterns}")
private String urlPatterns;
@Bean
public FilterRegistrationBean StreamRegistration() {
FilterRegistrationBean streamBean = new FilterRegistrationBean();
streamBean.setDispatcherTypes(DispatcherType.REQUEST);
streamBean.setFilter(new StreamFilter());
streamBean.addUrlPatterns(urlPatterns);
streamBean.setName("StreamFilter");
streamBean.setOrder(Integer.MAX_VALUE);
Map<String, String> initParameters = new HashMap<>(16);
initParameters.put("excludes", excludes);
initParameters.put("enabled", enabled);
streamBean.setInitParameters(initParameters);
return streamBean;
}
}
4、yml文件
stream:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /api/file/*,/api/file/upload
# 匹配链接
urlPatterns: /api/*