java - 如何在HandlerInterceptor中读取请求体?

标签 java spring spring-boot spring-mvc

我有Spring Boot,我需要在数据库中记录用户操作,所以我编写了HandlerInterceptor:

@Component
public class LogInterceptor implements HandlerInterceptor {
@Autovired
private LogUserActionService logUserActionService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
throws IOException {
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    String url = request.getRequestURI();
    String queryString = request.getQueryString() != null ? request.getQueryString() : "";
    String body = "POST".equalsIgnoreCase(request.getMethod()) ? new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator())) : queryString;
    logUserActionService.logUserAction(userName, url, body);
    return true;
}
}

但是根据这个答案Get RequestBody and ResponseBody at HandlerInterceptor “RequestBody 只能读取一次”,所以据我了解,我读取输入流,然后 Spring 尝试执行相同的操作,但流已被读取,并且我收到错误:“缺少所需的请求正文...”

所以我尝试了不同的方法来制作缓冲输入流,即:

HttpServletRequest httpServletRequest = new ContentCachingRequestWrapper(request);
new BufferedReader(new InputStreamReader(httpServletRequest.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator()))

或者

InputStream bufferedInputStream = new BufferedInputStream(request.getInputStream());

但没有任何帮助 我也尝试使用

@ControllerAdvice
public class UserActionRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

但它只有正文,没有 URL 或请求参数等请求信息 也尝试使用过滤器,但结果相同。

所以我需要一种好方法来从请求中获取信息,例如用户、URL、参数、正文(如果存在)并将其写入数据库。

最佳答案

您可以使用Filter来记录请求正文。

public class LoggingFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        try {
            chain.doFilter(wrappedRequest, res);
        } finally {
            logRequestBody(wrappedRequest);
        }
    }

    private static void logRequestBody(ContentCachingRequestWrapper request) {

        byte[] buf = request.getContentAsByteArray();
        if (buf.length > 0) {
            try {
                String requestBody = new String(buf, 0, buf.length, request.getCharacterEncoding());
                System.out.println(requestBody);
            } catch (Exception e) {
                System.out.println("error in reading request body");
            }
        }
    }
}

这里要注意的主要一点是,您必须在过滤器链中传递 ContentCachingRequestWrapper 对象,否则您将无法在其中获取请求内容。

在上面的示例中,如果您使用 chain.doFilter(req, res)chain.doFilter(request, res) 那么您将不会获得请求正文wrappedRequest 对象。

关于java - 如何在HandlerInterceptor中读取请求体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60556148/

相关文章:

java - Spring启动示例: Can't access reSTLet from browser

java - 两个 docker 容器之间通信出现问题

java - Android CallLog Content Provider 引发 java.lang.IllegalArgumentException

multithreading - SpringFrameWork 注入(inject)的 bean 为空?

java - 部署 Spring MVC 应用程序时出现异常?

java - 类中的构造函数不能应用于 Spring Boot Controller 的给定类型

java - 如何在项目目录中包含 swagger 生成的类

java - 在 Swing 中,布局具有不同高度的组件

java - 如何在 Groovy 中经过一定时间后完成或终止进程?

java - 我们可以使用java向word模板中的现有表添加多行吗