【问题标题】:Spring MVC Get POST body before controllersSpring MVC 在控制器之前获取 POST 主体
【发布时间】:2019-03-20 13:53:57
【问题描述】:

我需要阅读 POST 请求正文而不使用它。

我已经在我的自定义 HandlerInterceptor 中以多种方式进行了尝试,但没有任何效果。我试图包装和缓存请求正文的所有尝试在某些时候都不起作用,甚至可能是因为我无法控制 Spring 所做的事情。

所以我想到了另一件事:在某些时候,Spring 会尝试将请求主体映射到一个对象并将其传递给正确的控制器。我可以在调用Controller之前拦截这个动作并获取那个对象吗?

【问题讨论】:

  • 为什么需要在请求处理之前读取正文?你需要用它做什么?您只能处理一次请求,因此如果不重复读取,它将无法工作(例如在 Spring 的日志过滤器中)。
  • 因为我更喜欢在单个点记录每个请求,而不是在每个控制器的每个方法中插入一个日志。
  • 因为 Spring 已经有特殊的过滤器,使用它们而不是自己滚动。还有其他现有的解决方案。归结为将响应存储在内存中并在请求包装器中实现读取。
  • 您是否为过滤器启用了调试日志记录?否则它不会记录任何内容。
  • 它只会记录正在处理的有效负载。如果你没有绑定/处理它不会记录的有效负载。

标签: java spring rest spring-mvc post


【解决方案1】:

在到达控制器之前从请求中读取请求正文后,您将无法在任何地方使用。所以你可以做的是在Filter 实现中从HttpServletRequest 读取正文并将其设置在ThreadLocal 变量中。然后你可以从ThreadLocal 中读取。下面是示例代码。

Filter内部实现类

try {
    YourModel yourModel = // Read the request body

    RequestContextHolder.setContext(yourModel);
}finally {
    RequestContextHolder.clearContext();
}

并且在当前请求中的任何时间点,您都可以执行以下操作。

RequestContextHolder.getContext();

这是RequestContextHolder

public class RequestContextHolder {

    private static final ThreadLocal<YourModel> THREAD_LOCAL = new ThreadLocal<>();

    public static void setContext(YourModel yourModel) {
        THREAD_LOCAL.set(yourModel);
    }

    public static YourModel getContext() {
       return THREAD_LOCAL.get();
    }

    public static void clearContext() {
       THREAD_LOCAL.remove();
    }
}

【讨论】:

  • 我不明白:在我的过滤器中,我可以在哪里获取请求正文?
  • 来自HttpServletRequest,您可以将主体解析为您的模型类。无论如何,你得到了解决方案。
  • 好的,但是使用哪种过滤方法?如果我解析请求正文,我会使用它。
  • doFilter() 方法中,当然,是的,你会使用它。但这是在ThreadLocal 中设置的,因此可以从当前请求中的任何位置访问它。
  • 这样Spring无法读取请求体,所以每次请求都会失败。
【解决方案2】:

我找到了一个解决方案:使用 CommonsRequestLoggingFilter Spring 甚至可以记录请求的负载。我发现的唯一麻烦是我只能在 afterRequest 方法中读取有效负载,因为在 beforeRequest 中不存在。

有关 CommonsRequestLoggingFilter here 的更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多