1. 程式人生 > >在filter中使用包裝類包裝request、response分別修改請求引數和修改響應結果

在filter中使用包裝類包裝request、response分別修改請求引數和修改響應結果

工作需要,要將請求和響應做一些處理,使得瀏覽器展示結果可控。

首先是在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。