我遇到一个老代码,里面有个自定义Filter ,里面通过自定义 HttpServletRequestWrapper 实现请求数据的可复读。我看到网上有不少优秀的解决方案,例如可以搜下关键字:
BodyReaderHttpServletRequestWrapper
大部分搜索结果思路都是一样的:
copy(inputstream), 转成 ByteArrayInputStream 缓存在 BodyReaderHttpServletRequestWrapper 的成员变量中。只不过方案们描述的都是基于一个前提:请求参数是 json 格式的,也就是说仅支持 application/json 的请求。如果传 form/data 就挂了。
优化思路也很简单:加上重写 getParameterValues 方法就行了。
package com.org.zm;
import org.apache.commons.collections.MapUtils;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
private Map parameterMap;
@Override
public String[] getParameterValues(String name) {
if(MapUtils.isNotEmpty(parameterMap)) {
return parameterMap.get(name);
}
return null;
}
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
parameterMap = request.getParameterMap();
body = StreamUtils.copyToByteArray(request.getInputStream());
}
public String getBodyString(){
return new String(body,Charset.forName("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) {
}
};
}
}
重要:该方案支持 json 数据的缓存 ,也支持了 formdata 的数据缓存,还有文件类型的还没支持,如果涉及到文件接口的话,还需要再扩展