【问题标题】:How to get request body params in spring filter?如何在弹簧过滤器中获取请求正文参数?
【发布时间】:2021-01-19 11:08:52
【问题描述】:

我想通过 Spring 过滤器或方面在 http 请求中记录请求参数。 我尝试了不同的方法,但请求参数为空或方法未被调用。 我正在使用 POSTMAN,它是一个 POST 请求

http://localhost:8080/AvailableData

示例请求正文:

{"keyUserAgent":"CFNetwork/1209 Darwin/20.2.0","locale":"en_US","eid":"8904977033","sessionId":"VGA-G20201030-776878787-1AD5-11EB- 895C-H78789GJJH"}

方法1:这里调用了 beforeRequest() 的“@Override”方法,但没有调用我创建的重载方法(我添加了@RequestBody 以按照其他解决方案获取正文)。

@Component
public class CustomLoggingFilter extends AbstractRequestLoggingFilter {
      
            protected void beforeRequest(HttpServletRequest request, String message,@RequestBody RequestDTO requestBody) {
            requestBody.getKeyUserAgent();
            requestBody.getEid();
            System.out.println("Eid: "+requestBody.getEid());
            System.out.println("getKeyUserAgent: "+requestBody.getKeyUserAgent());
            
        }  
        
    }

方法2:这里是null

@Aspect
@Component
@Order(1)
public class LogAspect {

    private final static Logger logger = LoggerFactory.getLogger(LoggerAspect.class);
      @Around("allControllerMethods() && args(..,@annotation(org.springframework...RequestBody) requestBody) ")
      public Object controllerEvents(ProceedingJoinPoint jp, Object requestBody) throws Throwable {
            
          ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
             HttpServletRequest request = attributes.getRequest();
             MethodSignature signature = (MethodSignature) jp.getSignature();
              Method method = signature.getMethod();
              Object resObject = jp.proceed();
              Object sessionId = attributes.getSessionId()
              if (requestBody != null) {
                  String keyUserAgent = request.getParameter("keyUserAgent");
                  System.out.println("keyUserAgent : " + keyUserAgent);
                  
                }
              
          return resObject;
      } 

【问题讨论】:

    标签: java spring spring-boot


    【解决方案1】:

    首先,从 HttpRequest 读取数据以进行日志记录和稍后进行处理存在问题,因为类 HttpServletRequest 只允许读取其内容一次,任何重复尝试读取它都会导致异常。因此,spring boot 提供了一个使用类ContentCachingRequestWrapper 的解决方案。这个想法是您在过滤器中读取请求的整个上下文,然后将内容复制到允许多次读取的包装类中。之后,您将使用包装类(间接实现 HttpServletRequest)继续该链。因此,现在在您的一个过滤器中(必须在将 HttpServletRequest 替换为 ContentCachingRequestWrapper 的过滤器之后进行配置,您可以读取并记录您的请求参数,稍后您仍然可以读取您的处理请求。我在我们的项目中实现了它并且它有效就像一个魅力。这里有一些文章的链接解释如何做到这一点。Reading HttpServletRequest Multiple Times in SpringJava Code Examples for org.springframework.web.util.ContentCachingRequestWrapper

    【讨论】:

    • 感谢@Michael 分享这一见解。这很有帮助,虽然它可以完成这项工作,但它会强制创建多个请求和过滤器类。有没有更简单的方法来获得这个。这样做的原因是为了增强应用程序的日志记录,如果它确实对现有过滤器造成任何影响,那么这些许多代码更改将吸引大量的 QA 和测试。请指教。
    • 还有一件事它会打印整个正文,但是如何从 keyUserAgent、eid、sessionId 等 json 正文中提取每个项目/键?
    • 好的检查并在控制器中发现请求正文为空并导致失败,所以它对我不起作用。
    • 首先,我不知道更简单的解决方案,我想没有一个,因为 Spring 提供了这个作为他们自己的标准解决方案。其次,如果现在某些东西对您不起作用,那么很有可能它在您的代码中,因为很多人(包括我)都使用了这个解决方案并且它对我们有用。所以,做一些调试,你可能会找到问题的原因
    • 正如你所说的那样它会起作用,因为你可能没有在控制器等其他类中使用“HttpServletRequest”,在我的情况下,有一段现有的代码,如使用 HttpServletRequest 参数的控制器(我不应该理想地接触)所以我想除非它也开始使用 ContentCachingRequestWrapper 它可能不适用于我的情况,对吧?
    猜你喜欢
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 2016-05-25
    相关资源
    最近更新 更多