开发中,经常会有这样的需求 ,需要从请求体中拿出特殊的参数进行处理或者将整个请求体做为日志记录。那应该如何获取请求体或者响应体呢 ?方法很多,这里给出一个方法进行处理。下面是demo可以直接使用。

本次使用方法主要是通过 RequestWrapper  和 ResponseWrapper 进行实现。

1、创建请求wrapper

@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {

    private final String body;

    public RequestWrapper(HttpServletRequest request) {
        super(request);

        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try (InputStream inputStream = request.getInputStream()) {
            if(inputStream != null){
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            }
        } catch (Exception e) {
            log.error("RequestWrapper read error :{}",e.getMessage());
        } finally {
            IoUtil.close(bufferedReader);
        }
        body = stringBuilder.toString();
    }

    /**
     * 将getInputStream重新,让它能重复获取到body里的内容,这样才不会影响后续的流程
     * @return
     * @throws IOException
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }

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

    /**
     * 重写获取 字符流的方式
     * @return
     */
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream(), StandardCharsets.UTF_8));
    }


    /**
     * 获取body
     * @return
     */
    public String getBody() {
        return this.body;
    }
}

2、创建响应wrapper

@ControllerAdvice
public class ResponseWrapper implements ResponseBodyAdvice<Object> {

    private static final Integer MAX_LENGTH = 1000;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String result ;
        if(body instanceof JSON){
            JSON jsonResult = (JSON) body;
            result = JSON.toJSONString(jsonResult);
        }else{
            result = JSON.toJSONString(body);
        }
        Integer length = result.length() > MAX_LENGTH ? MAX_LENGTH :  result.length();
        result = result.substring(0,length);
        HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession httpSession = httpServletRequest.getSession(true);
        //放到缓存里,以便于可以在HandlerInterceptor拦截里取出并打印出返回结果
        httpSession.setAttribute("mybody", result);
        return body;
    }
}

3、创建过滤器


@Component
@WebFilter(filterName = "HttpServletRequestFilter", urlPatterns = "/")
@Order(10000)
public class HttpServletRequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        }
        //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
        // 在chain.doFiler方法中传递新的request对象
        if(null == requestWrapper) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

4、在拦截器中使用获取请求参数

通过拦截器变更了请求,直接进行转换获取


@Slf4j
@Component
public class OpenapiInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
       
        String requestBody = StringUtils.EMPTY;
        if (request instanceof RequestWrapper) {
            requestBody = ((RequestWrapper) request).getBody();
        }
         
        return true;
    }
}

5、在拦截器中使用获取响应参数

响应获取是在响应拦截的时候,通过session缓存写入后获取的值


@Slf4j
@Component
public class OpenapiInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
       
         HttpSession httpSession = request.getSession();
//myBody是在响应的时候写入到Session的key,可以看responseWrapper
        String result = (String)httpSession.getAttribute("myBody");
         
        return true;
    }
}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐