任何情况下的HttpServletRequest参数无法重复读取【formdata/json/get/post】
我也是照着网上的大部分方案,把流拷贝出来,这样确实解决了我使用json传递的问题,但是我是用的方法不能解决formdata的传递;
·
request的参数会使用流的方式获取,这就意味着读取一次之后会关闭,如果使用过滤器/拦截器进行参数处理之后,controller层就无法获取参数了,可能会报的错误 如:stream closed
我也是照着网上的大部分方案,把流拷贝出来,这样确实解决了我使用json传递的问题,但是我是用的方法不能解决formdata的传递;其实这个wrapper框架已经提供给了我们:
org.springframework.web.util.ContentCachingRequestWrapper
ContentCachingRequestWrapper
我们不需要去封装方法处理请求流,使用spring自带的requestWrapper,这里有个问题:spring缓存的请求参数只有在调用流之后才会有效,这时候在filter或者拦截器之前访问还是获取不到请求参数,这样做的好处就是节约内存,如果我们自己的应用可以采用第二种方法;
/**
* 配合@ServletComponentScan扫描自定义的过滤器即可
* @author JGMa
*/
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class RequestWrapperFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void destroy() {
Filter.super.destroy();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 主要是这里
chain.doFilter(new ContentCachingRequestWrapper((HttpServletRequest) request), response);
}
}
拦截器中使用
ContentCachingRequestWrapper requestWrapper = null;
// 注意不要二次包装
if (request instanceof ContentCachingRequestWrapper){
requestWrapper = (ContentCachingRequestWrapper)request;
}else {
requestWrapper = new ContentCachingRequestWrapper(request);
}
// 读取请求参数
String jsonPostParam = StringUtils.toEncodedString(requestWrapper.getContentAsByteArray(), Charset.forName(requestWrapper.getCharacterEncoding()));
方法二:自定义缓冲流
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* @author JGMa
*/
public class RepeatableInputStream extends ServletInputStream {
// 底层是个字节数组
final ByteArrayInputStream byteArrayInputStream;
public RepeatableInputStream(byte[] requestBodyBytes) {
// 实例化的时候就把读取到的字节缓存起来
this.byteArrayInputStream =
new ByteArrayInputStream(requestBodyBytes);
}
/* 下面的都是ServletInputStream的必要重写方法 */
@Override
public boolean isFinished() {
return byteArrayInputStream.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
// Not implemented
}
@Override
public int read() throws IOException {
// 直接从缓存读取
return byteArrayInputStream.read();
}
}
import org.springframework.util.StreamUtils;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* @author JGMa
*/
public class RepeatableRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
private Charset charset;
public RepeatableRequestWrapper(HttpServletRequest request, Charset charset) throws IOException {
super(request);
body = StreamUtils.copyToByteArray(request.getInputStream());
this.charset = charset;
}
public RepeatableRequestWrapper(HttpServletRequest request) throws IOException {
this(request, StandardCharsets.UTF_8);
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new RepeatableInputStream(body);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(), charset));
}
/* 两个读取body的辅助方法 */
public byte[] getRequestBodyBytes() {
return body;
}
public String getRequestBodyString() {
return new String(body,charset);
}
}
使用
RepeatableRequestWrapper requestWrapper = null;
if (request instanceof RepeatableRequestWrapper){
requestWrapper = (RepeatableRequestWrapper)request;
}else {
requestWrapper = new RepeatableRequestWrapper(request);
}
// 获取请求中的JSON数据
String json = requestWrapper.getRequestBodyString();
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)