解决request无法重复读取数据流问题

2018-09-05  本文已影响0人  yuanjian

去年在开放中遇到过一个问题,因为项目重构,数据库等完全的重构,所以线上产生了两套环境。由于我们做的是开放平台,已经有很多开发者对接了,所以老的服务需要保留,一时间需要维护两套服务,老服务中很多应用遇到问题,无法修改应用信息,需要联系客服然后我们手动修改,非常麻烦。于是项目组决定将老的数据订正到新的表中,然后在老的服务中做一次向上的转发,如果失败了再走老的平台。所以需要重复读取HTTP请求的body数据,团队leader给了思路,写一个request的包装类,将读到的inputstream缓存到内存中,便可以重复读取。先上代码:


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.ByteArrayInputStream;
import java.io.IOException;
/**
 * HttpServletRequestWrapper的包装类,用于重复读取inputStream
 *
 * Created by yuanjian on 10/17/17
 * @author liuyj@shinemo.com
 */
public class InputStreamReadRepeatableRequestWrapper extends HttpServletRequestWrapper {
    private ServletInputStream inputStream;
    public InputStreamReadRepeatableRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (this.getContentLength() < 1) {
            return null;
        }
        if (this.inputStream == null) {
            this.inputStream = new InputStreamReadRepeatableRequestWrapper.ReadRepeatableInputStream(this.getRequest().getInputStream(), this.getRequest().getContentLength());
        }
        return inputStream;
    }
    private class ReadRepeatableInputStream extends ServletInputStream {
        private final ByteArrayInputStream bi;
        private ReadRepeatableInputStream(ServletInputStream inputStream, int length) throws IOException {
            if (length > 0) {
                byte[] bytes = new byte[length];
                IOUtils.read(inputStream, bytes, 0, length);
                inputStream.read(bytes, 0, length);
                bi = new ByteArrayInputStream(bytes, 0, length);
            } else {
                bi = null;
            }
        }
        @Override
        public int read() throws IOException {
            int bt = -1;
            if (bi != null) {
                bt = this.bi.read();
                if (bt == -1) {
                    this.bi.reset();
                }
            }
            return bt;
        }
        @Override
        public void reset() {
            this.bi.reset();
        }
        @Override
        public boolean isFinished() {
            return false;
        }
        @Override
        public boolean isReady() {
            return false;
        }
        @Override
        public void setReadListener(ReadListener readListener) {

        }
    }
}

然后新增一个filter

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * @author liuyj@shinemo.com
 */
public final class RequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        InputStreamReadRepeatableRequestWrapper request = new InputStreamReadRepeatableRequestWrapper((HttpServletRequest) servletRequest);
        filterChain.doFilter(request, servletResponse);
    }
    @Override
    public void destroy() {

    }
}

最后只需要在web.xml中配置此filter即可。

上一篇下一篇

猜你喜欢

热点阅读