Spring MVC 在处理程序拦截器中获取请求主体和响应主体

5jvtdoz2  于 2023-03-13  发布在  Spring
关注(0)|答案(8)|浏览(172)

我必须实现的逻辑是记录所有主体被提供给DB的请求。
所以我决定用途:HandlerInterceptorafterCompletion方法。有两个参数传递给此方法HttpServletRequestHttpServletResponse
问题是:如何从提供的对象中获取RequestBodyResponseBody
据我所知,在Controller中我们可以使用@RequestBody@ResponseBody。我可以在HandlerInterceptor中重用它们吗?

yftpprvb

yftpprvb1#

您可以扩展RequestBodyAdviceAdapter并实现afterBodyRead方法:

@ControllerAdvice
public MyRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
            Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {

        // write body -your input dto- to logs or database or whatever

        return body;
    }

}

RequestBodyAdvice在HandlerInterceptor之前的请求链中预先设置。它正好在http请求输入流转换为您的对象之后。

kx7yvsdv

kx7yvsdv2#

据我所知,RequestBodyResponseBody只能读一次。所以你不应该在Interceptor中读它们。下面是一些explanation

41ik7eoe

41ik7eoe3#

正如其他人所说,你不能多次读取请求输入流或响应输出流,但是,你可以使用过滤器来替换原始的请求和响应对象,用这种方法你可以实现你的 Package 器和缓冲负载,这样你就可以使用它多少次。
下面是一个带有工作代码的repo:https://github.com/glaudiston/spring-boot-rest-payload-logging
只要在上面做一个mvn clean install,然后开心就行了。

$ java -jar target/rest-service-0.0.1-SNAPSHOT.jar                                                                                                                                                                                                                               

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)

2020-01-24 13:06:07.297  INFO 918 --- [           main] c.e.restservice.RestServiceApplication   : Starting RestServiceApplication v0.0.1-SNAPSHOT on ca275nt with PID 918 (/home/ggs/src/spring-boot-rest-payload-logging/target/rest-service-0.0.1-SNAPSHOT.jar started by ggs
in /home/ggs/src/spring-boot-rest-payload-logging)
2020-01-24 13:06:07.301  INFO 918 --- [           main] c.e.restservice.RestServiceApplication   : No active profile set, falling back to default profiles: default                                                                                                             
2020-01-24 13:06:08.331  INFO 918 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)                                                                                                                                 
2020-01-24 13:06:08.348  INFO 918 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-01-24 13:06:08.348  INFO 918 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]                                                                                                                              
2020-01-24 13:06:08.410  INFO 918 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext                                                                                                                           
2020-01-24 13:06:08.410  INFO 918 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1044 ms                                                                                                              
2020-01-24 13:06:08.627  INFO 918 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'                                                                                                                       
2020-01-24 13:06:08.787  INFO 918 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''                                                                                                                  
2020-01-24 13:06:08.791  INFO 918 --- [           main] c.e.restservice.RestServiceApplication   : Started RestServiceApplication in 1.928 seconds (JVM running for 2.319)                                                                                                      
2020-01-24 13:06:11.014  INFO 918 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'                                                                                                                    
2020-01-24 13:06:11.014  INFO 918 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'                                                                                                                                     
2020-01-24 13:06:11.022  INFO 918 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 8 ms
2020-01-24 13:06:11 [] INFO  RequestFilter:23 - doFilter, parsing request
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:64 - Request Method: POST
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:65 - Request Headers:
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:66 - host:localhost:8080
user-agent:curl/7.64.0
accept:*/*
content-length:32
content-type:application/x-www-form-urlencoded

2020-01-24 13:06:11 [] INFO  LogApiInterceptor:67 - Request body:
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:68 - testdata=123456789&test2=9876543
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:75 - Response Status: 200
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:76 - Response Headers:
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:77 -
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:78 - Response body:
2020-01-24 13:06:11 [] INFO  LogApiInterceptor:84 - {"id":1,"content":"Hello, World!"}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
$ curl -X POST --data "testdata=123456789&test2=9876543" http://localhost:8080/greeting
{"id":1,"content":"Hello, World!"}
fiei3ece

fiei3ece4#

下面是javadoc中针对HandlerInterceptor javadoc的相关语句。
请求处理完成后的回调,即呈现视图后。将在处理程序执行的任何结果上调用,从而允许正确的资源清理。
HandlerIntercepter Javadoc
无法访问请求正文(作为InputStream),因为请求已被读取。如果需要访问请求参数,可以使用请求对象通过调用- request.getParameter(“parameterName”)来实现;
无法访问响应正文,因为响应已呈现。这意味着响应已提交到输出流。

t9eec4r0

t9eec4r05#

您可以使用以下方法从HandlerInterceptorAdapter方法内部的HTTPServlet请求中获取请求主体:

request.getInputStream();

如果要将其与扫描仪一起使用,可以按如下方式指定扫描仪:

Scanner scanner = new Scanner(request.getInputStream(), "UTF-8");

然后你可以使用一些操作或扫描技巧来使用扫描器中的数据,或者你也可以使用Apache Commons IO将其赋给一个字符串:

String requestStr = IOUtils.toString(request.getInputStream());
u2nhd7ah

u2nhd7ah6#

这是一个很老的线程,但为了人们谁寻找一种方法来获得RequestBodyResponseBody从拦截器。
RequestBody,可以简单地使用IOUtils:

String requestBody= IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);

ResponseBody,我不得不使用HttpServletResponseCopier:

ServletLoggingFilter.HttpServletResponseCopier copier = (ServletLoggingFilter.HttpServletResponseCopier) response;
String responseBody = new String(copier.getCopy());
vd2z7a6w

vd2z7a6w7#

您可以使用自Spring 4.1以来可用的ResponseBodyAdvice,使用它可以在响应主体被写入客户机之前截取响应主体。
下面是一个例子:https://sdqali.in/blog/2016/06/08/filtering-responses-in-spring-mvc/

eh57zj3b

eh57zj3b8#

由于请求主体在拦截器中可用,而流在读取后不可用。如果您需要拦截器中的主体,然后在控制器中使用,则需要将其缓存在您自己的 Package 器中:https://tomsdevblog.com/read-message-body-in-request-interceptor/

相关问题