在gateway里使用Filter过滤器时,有时候需要多次读取request.getInputStream();
如果不作任何处理,只有第一次可以读取到body中的内容;
为了解决多次读取的问题,需要使用到HttpServletRequestWrapper;
包装类代码如下:
package com.demo.gateway.wrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* HttpServletRequest包装类
* @author shpan
* @date 2022-05-31
*/
public class MutilReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final Logger logger = LoggerFactory.getLogger(MutilReaderHttpServletRequestWrapper.class);
private final byte[] body;
/**
* 构建一个HttpServletRequest包装类
* 读取request中保存到body属性值
* @param request
* @throws IOException
*/
public MutilReaderHttpServletRequestWrapper (HttpServletRequest request) throws IOException {
super(request);
body = InputStreamToByte(request.getInputStream());
}
/**
* 流转 字节数组
* @param is 流
* @return 字节数组
*/
private byte[] InputStreamToByte(InputStream is) {
byte[] data = null;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
byte[] buffer=new byte[1024];
int ch;
while ((ch = is.read(buffer)) != -1) {
byteStream.write(buffer,0,ch);
}
data = byteStream.toByteArray();
} catch (IOException ex) {
logger.error("InputStreamToByte error:", ex);
} finally {
try {
byteStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 后面请求链需要读取流时根据写出的body重新生成一个新的流
*/
@Override
public ServletInputStream getInputStream() {
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) {
}
};
}
}
使用方式:
RequestContext ctx = RequestContext.getCurrentContext();
// 重新包装request,之后用包装后的request处理
HttpServletRequest request = new BodyReaderHttpServletRequestWrapper(ctx.getRequest());
InpustStream inputStream =request.getInputStream();
需要注意的是:如果后续Filter还有用到request,或者需要路由,则需要将request重新赋值给ctx,否则会抛异常;
// 原request流被取后数据length已经不一致了,需要重新赋值request
ctx.setRequest(request);