HttpServletRequest & HttpServletResponse 中 Body 的获取

HttpServletRequest & HttpServletResponse 中 Body 的获取获取 HttpServletRequest 中的请求体 HttpServletRequest#getInputStream , reset()

欢迎大家来到IT世界,在知识的湖畔探索吧!

获取 HttpServletRequest 中的请求体

HttpServletRequest#getInputStream() 获取到请求的输入流,从该输入流中可以读取到请求体。不过这个流在被我们的代码 read 过后,之后的代码就会报错,因为流已经被我们读取过了 , 尝试使用 mark() , reset() 也是不行的,会抛出异常。可以通过将 HttpServletRequest 对象包装一层的方式来实现这个功能。

package org.hepeng.commons.http;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * 
 * @author he peng
 * @date 2018/9/11
 */
public class BodyCachingHttpServletRequestWrapper extends HttpServletRequestWrapper {
 private byte[] body;
 private ServletInputStreamWrapper inputStreamWrapper;
 public BodyCachingHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
 super(request);
 this.body = IOUtils.toByteArray(request.getInputStream());
 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body);
 this.inputStreamWrapper = new ServletInputStreamWrapper(byteArrayInputStream);
 resetInputStream();
 }
 private void resetInputStream() {
 this.inputStreamWrapper.setInputStream(new ByteArrayInputStream(this.body != null ? this.body : new byte[0]));
 }
 public byte[] getBody() {
 return body;
 }
 @Override
 public ServletInputStream getInputStream() throws IOException {
 return this.inputStreamWrapper;
 }
 @Override
 public BufferedReader getReader() throws IOException {
 return new BufferedReader(new InputStreamReader(this.inputStreamWrapper));
 }
 @Data
 @AllArgsConstructor
 private static class ServletInputStreamWrapper extends ServletInputStream {
 private InputStream inputStream;
 @Override
 public boolean isFinished() {
 return true;
 }
 @Override
 public boolean isReady() {
 return false;
 }
 @Override
 public void setReadListener(ReadListener readListener) {
 }
 @Override
 public int read() throws IOException {
 return this.inputStream.read();
 }
 }
}

欢迎大家来到IT世界,在知识的湖畔探索吧!

获取 HttpServletResponse 中的响应体

通过使用 ByteArrayOutputStream 将原 HttpSevletResponse 进行一层包装就可以实现。ByteArrayOutputStream 是将数据写入到它内部的缓冲区中,这样我们就可以获取到这个数据了。

欢迎大家来到IT世界,在知识的湖畔探索吧!package org.hepeng.commons.http;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
/**
 * @author he peng
 * @date 2018/10/1
 */
public class BodyCachingHttpServletResponseWrapper extends HttpServletResponseWrapper {
 private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 private HttpServletResponse response;
 public BodyCachingHttpServletResponseWrapper(HttpServletResponse response) {
 super(response);
 this.response = response;
 }
 public byte[] getBody() {
 return byteArrayOutputStream.toByteArray();
 }
 @Override
 public ServletOutputStream getOutputStream() {
 return new ServletOutputStreamWrapper(this.byteArrayOutputStream , this.response);
 }
 @Override
 public PrintWriter getWriter() throws IOException {
 return new PrintWriter(new OutputStreamWriter(this.byteArrayOutputStream , this.response.getCharacterEncoding()));
 }
 @Data
 @AllArgsConstructor
 private static class ServletOutputStreamWrapper extends ServletOutputStream {
 private ByteArrayOutputStream outputStream;
 private HttpServletResponse response;
 @Override
 public boolean isReady() {
 return true;
 }
 @Override
 public void setWriteListener(WriteListener listener) {
 }
 @Override
 public void write(int b) throws IOException {
 this.outputStream.write(b);
 }
 @Override
 public void flush() throws IOException {
 if (! this.response.isCommitted()) {
 byte[] body = this.outputStream.toByteArray();
 ServletOutputStream outputStream = this.response.getOutputStream();
 outputStream.write(body);
 outputStream.flush();
 }
 }
 }
}

flush() 函数是必须提供的 ,否则流中的数据无法响应到客户端 , ByteArrayOutputStream 没有实现 flush() 。像 SpringMVC 这类框架会去调用这个响应输出流中的 flush() 函数 ,而且有可能在出现多次调用的情况,多次调用会产生问题使得客户端得到错误的数据,比如这样的 :

{“errorCode”:30001,”errorMsg”:”用户未认证”,”token”:null,”entity”:null}{“errorCode”:30001,”errorMsg”:”用户未认证”,”token”:null,”entity”:null} ,出现这种情况就说明 flush() 被调用了两次。所以需要在这里判断一下 HttpServletResponse#isCommitted() 。

获取请求体、相应体的包装类在 Filter 中的使用

package org.hepeng.commons.http.filter;
import com.tepin.commons.http.BodyCachingHttpServletRequestWrapper;
import com.tepin.commons.http.BodyCachingHttpServletResponseWrapper;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @author he peng
 * @date 2018/10/2
 */
public class DemoFilter implements Filter {
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
 }
 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
 BodyCachingHttpServletRequestWrapper requestWrapper =
 new BodyCachingHttpServletRequestWrapper((HttpServletRequest) request);
 byte[] requestBody = requestWrapper.getBody();
 // TODO do something
 BodyCachingHttpServletResponseWrapper responseWrapper =
 new BodyCachingHttpServletResponseWrapper((HttpServletResponse) response);
 chain.doFilter(requestWrapper , responseWrapper);
 byte[] responseBody = responseWrapper.getBody();
 // TODO do something
 }
 @Override
 public void destroy() {
 }
}

HttpServletRequest & HttpServletResponse 中 Body 的获取

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/48516.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信