工作需要,要将请求和响应做一些处理,使得浏览器展示结果可控。
首先是在filter中拦截一些请求,请求到达过滤器的时候,可以通过request获取请求中的一些参数。这时候,你可以修改数据中的一部分,然后,让过滤器放行。但是,运行中就发现问题了,整个请求直接400了。刚开始,不知道原因,以为是数据修改的不对,后来经过排查,终于找到了原因,这些数据读取一次之后,就相当于已经从数据流中取出过了,当服务器端再次读取参数的时候,此时已经没有任何东西了,所以请求就出问题了。
解决方案:给request添加一个包装类ParameterRequestWrapper,继承HttpServletRequestWrapper,先从request中取输入流,读取流中的数据,然后重写getInputStream()和getReader()方法。
filterChain.doFilter(reqWrapper,responseWrapper);//此处的response要写包装类
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
private byte[] buffer;
public ParameterRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
InputStream is = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int read = 0;
while ((read = is.read(buff)) > 0)
baos.write(buff, 0, read);
this.buffer = baos.toByteArray();
}
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
public ServletInputStream getInputStream() throws IOException
{
String buf = new String(buffer);
System.out.println("request的包装类中的内容:"+buf);
ParamUtil paramUtil = new ParamUtil();
boolean offlineLicense = paramUtil.isOfflineLicense(buf);
if (offlineLicense) {
String offlineToken = paramUtil.getOfflineToken(buf);
HttpClientUtil httpClientUtil = new HttpClientUtil();
String user = httpClientUtil.getUserByToken(offlineToken);
String endTime = httpClientUtil.getDisconnectUtil(user);
String resetParamsOffline = paramUtil.resetParamsOffline(buf, endTime);
if (resetParamsOffline==null) {//不修改
return new BufferedServletInputStream(this.buffer);
}else {//修改
byte[] bufs = new byte[1024];
bufs = resetParamsOffline.getBytes();
return new BufferedServletInputStream(bufs);
}
}
return new BufferedServletInputStream(this.buffer);
}
}
上面是修改请求参数的,还有,有时候需要对返回的结果进行修改,这时候也需要使用包装类。写一个ParameterResponseWrapper,继承HttpServletResponseWrapper,主要是重写getOutputStream()和getWriter()方法。
public class ParameterResponseWrapper extends HttpServletResponseWrapper{
private MyWriter myWriter;
private MyOutputStream myOutputStream;
public ParameterResponseWrapper(HttpServletResponse response) throws IOException{
super(response);
}
public ServletOutputStream getOutputStream() throws IOException{
myOutputStream = new MyOutputStream(super.getOutputStream());
return myOutputStream;
}
public PrintWriter getWriter() throws IOException{
myWriter = new MyWriter(super.getWriter());
return myWriter;
}
public MyWriter getMyWriter() {
return myWriter;
}
public MyOutputStream getMyOutputStream(){
return myOutputStream;
}
}
public class MyOutputStream extends ServletOutputStream{
private ServletOutputStream outputStream;
private byte[] bytes;
public MyOutputStream(ServletOutputStream outputStream){
this.outputStream = outputStream;
}
public void write(int b) throws IOException {
outputStream.write(b);
}
public void write(byte[] b, int off, int len) {
try {
gzipJson(b);
outputStream.write(bytes, off,bytes.length);
} catch (Exception e) {
// TODO: handle exception
System.out.println("输出流的输出错误是:"+e);
}
}
public void write(byte[] b) throws IOException {
super.write(b);
}
//解压json
public String getResponseJson(byte[] b) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(b);
GZIPInputStream gis =new GZIPInputStream(bis);
int length = -1;
byte [] b1 =new byte[1024];
while((length = gis.read(b1)) != -1){
bos.write(b1, 0, length);
}
bos.close();
String responseJson = bos.toString();
return responseJson;
}
//处理json
public String filterUser(byte[] b) throws IOException {
String username = "abc";
String responseJson = getResponseJson(b);
JSONObject jsonObject = JSONObject.fromObject(responseJson);
JSONArray jsonArray = jsonObject.getJSONArray("users");
if (jsonArray.size()>0) {
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject userObject = jsonArray.getJSONObject(i);
if (userObject.get("username").equals(username)) {
jsonArray.discard(i);
}
}
}
return jsonObject.toString();
}
//压缩处理后的json
public void gzipJson(byte[] b){
GZIPOutputStream gzipOutputStream ;
ByteArrayOutputStream byteout = new ByteArrayOutputStream();
try {
String filterUser = filterUser(b);
gzipOutputStream = new GZIPOutputStream(byteout);
gzipOutputStream.write(filterUser.getBytes("utf-8"));
gzipOutputStream.close();
bytes = byteout.toByteArray();
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
}
public byte[] getBytes(){
return bytes;
}
}
然后,就可以在filter中使用包装后的request和response了。
filterChain.doFilter(reqWrapper,responseWrapper);//此处的request和response要写包装类
最后,需要注意的是,你修改了response响应的内容,那么响应的,就要根据你响应的数据流的大小修改Content-Length。