实现 request body 重复读取的功能

This commit is contained in:
YunaiV 2021-02-20 20:18:54 +08:00
parent cb0945962d
commit 8e21b5200a
5 changed files with 45 additions and 120 deletions

View File

@ -44,15 +44,4 @@ public class FilterConfig {
return registration; return registration;
} }
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new RepeatableFilter());
registration.addUrlPatterns("/*");
registration.setName("repeatableFilter");
registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
return registration;
}
} }

View File

@ -1,45 +0,0 @@
package com.ruoyi.common.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
import com.ruoyi.common.utils.StringUtils;
/**
* Repeatable 过滤器
*
* @author ruoyi
*/
public class RepeatableFilter implements Filter {
@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
&& StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}

View File

@ -1,64 +0,0 @@
package com.ruoyi.common.filter;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import com.ruoyi.common.utils.http.HttpHelper;
/**
* 构建可重复读取inputStream的request
*
* @author ruoyi
*/
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
body = HttpHelper.getBodyString(request).getBytes("UTF-8");
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.dashboard.framework.web.config; package cn.iocoder.dashboard.framework.web.config;
import cn.iocoder.dashboard.framework.web.core.filter.RequestBodyCacheFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -50,4 +51,13 @@ public class WebConfiguration implements WebMvcConfigurer {
return new CorsFilter(source); return new CorsFilter(source);
} }
/**
* 创建 RequestBodyCacheFilter Bean可重复读取请求内容
*/
@Bean
@Order(Integer.MIN_VALUE)
public RequestBodyCacheFilter requestBodyCacheFilter() {
return new RequestBodyCacheFilter();
}
} }

View File

@ -0,0 +1,35 @@
package cn.iocoder.dashboard.framework.web.core.filter;
import cn.hutool.core.util.StrUtil;
import org.springframework.http.MediaType;
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;
/**
* Request Body 缓存 Filter实现它的可重复读取
*
* 基于 Spring 提供的 {@link org.springframework.web.util.ContentCachingRequestWrapper} 实现
*
* @author 芋道源码
*/
public class RequestBodyCacheFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
filterChain.doFilter(new ContentCachingRequestWrapper(request), response);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
// 只处理 json 请求内容
return !StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
}
}