1. 程式人生 > >如何在ServletResponse,HTTPServletResponse或者Filter中獲取HTTP的內容

如何在ServletResponse,HTTPServletResponse或者Filter中獲取HTTP的內容

      由於HTTPServletResponse只提供了getWriter和getOutputStream方法,並未提供獲取報文體的方法。如果在開發時遇到相應需求,可以使用HTTPServletResponseWrapper重新構造response。具體方法如下所示,例項為spring boot的一個過濾器,該示例用於演示如何將系統的HTTPServletResponse替換為可以獲得報文內容的自定義HTTPServletResponse。


import java.io.ByteArrayOutputStream;
import java.io.IOException;


import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;





@WebFilter(urlPatterns="/*" ,filterName="responseFilter")
public class ResponseFilter implements Filter{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		ServletResponseWrapper responseWrapper=new ServletResponseWrapper((HttpServletResponse)arg1);
		arg2.doFilter(arg0, responseWrapper);
		System.out.println(((HttpServletRequest)arg0).getServletPath());
		System.out.println(responseWrapper.getResponseBody());
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}
	
	public static class MonitorOutoutStream extends ServletOutputStream{

		private ServletOutputStream output;
		private ByteArrayOutputStream copy=new ByteArrayOutputStream();
		
		
		
		public MonitorOutoutStream(ServletOutputStream output) {
			super();
			this.output = output;
		}

		@Override
		public boolean isReady() {
			// TODO Auto-generated method stub
			return output.isReady();
		}

		@Override
		public void setWriteListener(WriteListener arg0) {
			// TODO Auto-generated method stub
			output.setWriteListener(arg0);
		}

		@Override
		public void write(int b) throws IOException {
			// TODO Auto-generated method stub
			output.write(b);
			copy.write(b);
		}

		@Override
		public void write(byte[] b) throws IOException {
			// TODO Auto-generated method stub
			output.write(b);
			copy.write(b);
		}

		@Override
		public void write(byte[] b, int off, int len) throws IOException {
			// TODO Auto-generated method stub
			output.write(b,off,len);
			copy.write(b,off,len);
		}
		
		public byte[] getWroteInfo() {
			return copy.toByteArray();
		}

		@Override
		public void flush() throws IOException {
			// TODO Auto-generated method stub
			output.flush();
			copy.close();
		}

		@Override
		public void close() throws IOException {
			// TODO Auto-generated method stub
			output.close();
			copy.close();
		}
		
		
	}
	
	public static class ServletResponseWrapper extends HttpServletResponseWrapper{
        
		 private  volatile MonitorOutoutStream mos;
		
		public ServletResponseWrapper(HttpServletResponse response) {
			super(response);
			// TODO Auto-generated constructor stub
		}
        
		
		@Override
		public ServletOutputStream getOutputStream() throws IOException {
			// TODO Auto-generated method stub
			 if(mos==null){
		            synchronized (this) {
		                if(mos==null){      
		                    mos = new  MonitorOutoutStream(super.getOutputStream());
		                }
		            }
		        }
			 return mos;
		}
		
		public String getResponseBody(){
		
				return new String(mos.getWroteInfo());
			
		
	}
	}
}

本文通過重寫getOutputstream方法,替換原本的ServletOutputStream。重寫所有的ServletOutputStream方法。當ServletOuputStream的write被呼叫的時候,同時寫入一份到我們的copy當中,這樣來達到獲取報文的目的。

不過,就一般而言,從response獲取資訊這種需求應該是不存在的,當你發現需要用到上述程式碼時,從程式碼設計結構的角度可能有更好的解決方案。