Springboot 使用【过滤器】实现在请求到达 Controller 之前修改请求体参数和在结果返回之前修改响应体-前情提要

时间:2024-04-08 07:01:00

在项目中需要使用过滤器 在请求调用 Controller 方法前修改请求参数和在结果返回之前修改返回结果

在 Controller 中定义如下接口:

@PostMapping("/hello")
public JSONObject hello(@RequestBody Map<String, Object> params) {
    return JSONObject.parseObject(JSON.toJSONString(params));
}

定义的过滤器如下:

public class ServNoFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 获取请求体内容
        String requestBody = getRequestBody(httpServletRequest);
        // 业务处理
        ......
        // 放行
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private String getRequestBody(HttpServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(request.getReader());
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    }
}

此时启动项目,访问接口,则会在控制台打印如下异常信息:Request processing failed; nested exception is java.lang.IllegalStateException: getReader() has already been called for this request

表示在过滤器中已经通过 request.getReader() 方法将请求流读取。

如果在过滤器中将 getReader() 换成 getInputStream() 就会报请求体为空异常:org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing

这是因为在 Servlet 中,请求对象的输入流只能被读取一次。而在第一次读取请求体时,Servlet 容器会将请求体保存在内存中,并将其解析成相应的请求参数和请求头信息。如果在后续的处理中再次读取请求体,就可能会导致数据错误或异常。