需求背景
系统需要对请求体内容进行校验计算是否合法,因此准备通过拦截器 Interceptor 来进行统一处理。

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String param = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
        // 进行校验处理
        return check(param);
    }
}

由于该拦截器读取了一次 inputStream, 导致 Spring框架在赋值给接口 @RequestBody 参数时无法再获取到 inputStream 导致程序出现错误:Required request body is missing

解决方法

  1. 扩写ServletInputStream
public class RequestBodyInputStreamWrapper extends ServletInputStream {

    private ByteArrayInputStream bais;
    private ServletInputStream wrapped;

    public RequestBodyInputStreamWrapper(ServletInputStream wrapped) {
        this.wrapped = wrapped;
    }

    // 缓存内容用于后期读取
    public byte[] resetReading(byte[] bytes) {
        this.bais = new ByteArrayInputStream(bytes);
        return bytes;
    }

    @Override
    public int read() throws IOException {
        return bais.read();
    }

    @Override
    public boolean isFinished() {
        return wrapped.isFinished();
    }

    @Override
    public boolean isReady() {
        return wrapped.isReady();
    }

    @Override
    public void setReadListener(ReadListener readListener) {
        wrapped.setReadListener(readListener);
    }
}
  1. 扩写请求类 ContentCachingRequestWrapper
public class RequestBodyContentWrapper extends ContentCachingRequestWrapper {

    private RequestBodyInputStreamWrapper bodyProcessorIS;

    public RequestBodyContentWrapper(ContentCachingRequestWrapper wrapped) throws IOException {
        super(wrapped);
        this.bodyProcessorIS = new RequestBodyInputStreamWrapper(wrapped.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() {
        return bodyProcessorIS;
    }

    public byte[] prepareInputStream() throws IOException {
        return bodyProcessorIS.resetReading(super.getInputStream().readAllBytes());
    }
}
  1. 过滤器中将 HttpServletRequest 替换为包装后的类 RequestBodyContentWrapper
public class RequestBodyWrapperFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper cacheRequest = new ContentCachingRequestWrapper(request);
        RequestBodyContentWrapper readableRequest = new RequestBodyContentWrapper(cacheRequest);
        // 调用该方法来缓存请求体的内容
        readableRequest.prepareInputStream();
        filterChain.doFilter(readableRequest, response);
    }
}
  1. 拦截器中获取请求体内容
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        RequestBodyContentWrapper request1 = (RequestBodyContentWrapper) request;
        String param = new String(request1.getContentAsByteArray());
        // 进行校验处理
        return check(param);
    }
}

参考资料

posted @ 2024-12-17 14:31 红枫星空 阅读(39) 评论(0) 推荐(0) 编辑
摘要: 遇到的问题是解决方案中部分项目无法加载,提示需要缺少的web组件才能加载该项目,是否通过WEB安装组件来网络安装,点击确定以后就什么也没有了。网上查阅了一番,结合自己的使用情况(在家里用的是vs2013,在公司用的是vs2010),发现应该是缺少IIS Express组件。-------------... 阅读全文
posted @ 2015-04-15 11:01 红枫星空 阅读(1500) 评论(0) 推荐(0) 编辑
摘要: 系统环境:windows2008 X64IIS版本:iis7oracle客户端版本:11g,另外装了32位的客户端。网站.net framework版本: 4.0目前状况,IIS可以正常运行,程序页面没有调用到数据库的可以正常运行。调用到数据库的,就报 “System.Data.OracleClie... 阅读全文
posted @ 2014-05-29 13:40 红枫星空 阅读(2680) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示