在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。








  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现异步Servlet的反向代理功能,需要按照以下步骤进行操作: 1. 在Filter使用异步上下文(AsyncContext)对象,开启异步处理模式。 ``` HttpServletRequest request = (HttpServletRequest) servletRequest; final AsyncContext asyncContext = request.startAsync(); ``` 2. 在异步上下文添加异步操作完成的回调函数,用于在异步操作完成时进行处理。 ``` asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { // 异步操作完成时的处理逻辑 } // 其他回调函数的实现 }); ``` 3. 创建一个新的ServletRequestServletResponse对象,用于在异步操作处理请求响应。 ``` ServletRequest asyncRequest = asyncContext.getRequest(); ServletResponse asyncResponse = asyncContext.getResponse(); ``` 4. 创建一个新的HttpRequest和HttpResponse对象,用于向目标Servlet或JSP页面发起HTTP请求。 ``` String targetUrl = "http://localhost:8080/targetServlet"; HttpRequest httpRequest = new HttpRequest(asyncRequest, targetUrl); HttpResponse httpResponse = new HttpResponse(asyncResponse); ``` 其,HttpRequest和HttpResponse对象是自定义的用于包装requestresponse的类。 5. 使用HttpRequest对象,将请求转发给目标Servlet或JSP页面,并在异步操作完成时,调用HttpResponse对象的writeToAsyncResponse()方法,将目标Servlet或JSP页面的响应结果写入异步ServletResponse对象的输出流,最后调用异步上下文的complete()方法。 ``` HttpProxy httpProxy = new HttpProxy(); httpProxy.doPost(httpRequest, httpResponse); httpResponse.writeToAsyncResponse(); asyncContext.complete(); ``` 6. 在HttpRequest和HttpResponse对象编写具的转发和响应处理逻辑,确保异步操作能够正常完成,并且在异步操作完成后正确处理响应结果。 需要注意的是,在实现异步Servlet的反向代理功能时,应该避免阻塞当前请求线程,确保异步操作能够快速完成。同时,也需要注意HttpRequest和HttpResponse对象的一些设置,如请求方法、请求参数响应结果的读写等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值