Java Spring Boot 添加 Http 请求拦截器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31082981/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:37:17  来源:igfitidea点击:

Spring Boot Adding Http Request Interceptors

javaspringspring-mvcspring-boot

提问by riship89

What is the right way to add HttpRequest interceptors in spring boot application? What I want to do is log requests and responses for every http request.

在 Spring Boot 应用程序中添加 HttpRequest 拦截器的正确方法是什么?我想要做的是记录每个 http 请求的请求和响应。

Spring boot documentation does not cover this topic at all. (http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/)

Spring boot 文档根本不涉及这个主题。(http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

I found some web samples on how to do the same with older versions of spring, but those work with applicationcontext.xml. Please help.

我找到了一些关于如何使用旧版本 spring 执行相同操作的 Web 示例,但这些示例适用于 applicationcontext.xml。请帮忙。

采纳答案by ikumen

Since you're using Spring Boot, I assume you'd prefer to rely on Spring's auto configuration where possible. To add additional custom configuration like your interceptors, just provide a configuration or bean of WebMvcConfigurerAdapter.

由于您使用的是 Spring Boot,我假设您更愿意尽可能依赖 Spring 的自动配置。要添加额外的自定义配置,如拦截器,只需提供一个配置或WebMvcConfigurerAdapter.

Here's an example of a config class:

下面是一个配置类的例子:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

  @Autowired 
  HandlerInterceptor yourInjectedInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(...)
    ...
    registry.addInterceptor(getYourInterceptor()); 
    registry.addInterceptor(yourInjectedInterceptor);
    // next two should be avoid -- tightly coupled and not very testable
    registry.addInterceptor(new YourInterceptor());
    registry.addInterceptor(new HandlerInterceptor() {
        ...
    });
  }
}

NOTEdo not annotate this with @EnableWebMvc, if you want to keep Spring Boots auto configuration for mvc.

注意不要使用 @EnableWebMvc 对此进行注释,如果您想为 mvc保留Spring Boots 自动配置

回答by Magnus

You might also consider using the open source SpringSandwich library which lets you directly annotate in your Spring Boot controllers which interceptors to apply, much in the same way you annotate your url routes.

您还可以考虑使用开源 SpringSandwich 库,它允许您直接在 Spring Boot 控制器中注释要应用的拦截器,与注释 url 路由的方式非常相似。

That way, no typo-prone Strings floating around -- SpringSandwich's method and class annotations easily survive refactoring and make it clear what's being applied where. (Disclosure: I'm the author).

那样的话,就不会出现容易打错字的字符串——SpringSandwich 的方法和类注释很容易在重构中幸存下来,并清楚地说明应用在哪里。(披露:我是作者)。

http://springsandwich.com/

http://springsandwich.com/

回答by sunitha

To add interceptor to a spring boot application, do the following

要将拦截器添加到 Spring Boot 应用程序,请执行以下操作

  1. Create an interceptor class

    public class MyCustomInterceptor implements HandlerInterceptor{
    
        //unimplemented methods comes here. Define the following method so that it     
        //will handle the request before it is passed to the controller.
    
        @Override
        public boolean preHandle(HttpServletRequest request,HttpServletResponse  response){
        //your custom logic here.
            return true;
        }
    }
    
  2. Define a configuration class

    @Configuration
    public class MyConfig extends WebMvcConfigurerAdapter{
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
        }
    }
    
  3. Thats it. Now all your requests will pass through the logic defined under preHandle() method of MyCustomInterceptor.

  1. 创建拦截器类

    public class MyCustomInterceptor implements HandlerInterceptor{
    
        //unimplemented methods comes here. Define the following method so that it     
        //will handle the request before it is passed to the controller.
    
        @Override
        public boolean preHandle(HttpServletRequest request,HttpServletResponse  response){
        //your custom logic here.
            return true;
        }
    }
    
  2. 定义配置类

    @Configuration
    public class MyConfig extends WebMvcConfigurerAdapter{
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
        }
    }
    
  3. 就是这样。现在您的所有请求都将通过 MyCustomInterceptor 的 preHandle() 方法下定义的逻辑。

回答by sedooe

WebMvcConfigurerAdapterwill be deprecated with Spring 5. From its Javadoc:

WebMvcConfigurerAdapter将被 Spring 5 弃用。从它的Javadoc

@deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made possible by a Java 8 baseline) and can be implemented directly without the need for this adapter

@deprecated as of 5.0 {@link WebMvcConfigurer} 具有默认方法(由 Java 8 基线实现)并且可以直接实现而无需此适配器

As stated above, what you should do is implementing WebMvcConfigurerand overriding addInterceptorsmethod.

如上所述,您应该做的是实现WebMvcConfigurer和覆盖addInterceptors方法。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyCustomInterceptor());
    }
}

回答by user2532195

I had the same issue of WebMvcConfigurerAdapter being deprecated. When I searched for examples, I hardly found any implemented code. Here is a piece of working code.

我有同样的问题,即 WebMvcConfigurerAdapter 被弃用。当我搜索示例时,我几乎找不到任何已实现的代码。这是一段工作代码。

create a class that extends HandlerInterceptorAdapter

创建一个扩展 HandlerInterceptorAdapter 的类

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import me.rajnarayanan.datatest.DataTestApplication;
@Component
public class EmployeeInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(DataTestApplication.class);
    @Override
    public boolean preHandle(HttpServletRequest request, 
            HttpServletResponse response, Object handler) throws Exception {

            String x = request.getMethod();
            logger.info(x + "intercepted");
        return true;
    }

}

then Implement WebMvcConfigurer interface

然后实现 WebMvcConfigurer 接口

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import me.rajnarayanan.datatest.interceptor.EmployeeInterceptor;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    EmployeeInterceptor employeeInterceptor ;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(employeeInterceptor).addPathPatterns("/employee");
    }
}

回答by Xenonite

Since all responses to this make use of the now long-deprecated abstract WebMvcConfigurer Adapter instead of the WebMvcInterface (as already noted by @sebdooe), here is a working minimal example for a SpringBoot (2.1.4) application with an Interceptor:

由于对此的所有响应都使用现已弃用的抽象 WebMvcConfigurer Adapter 而不是 WebMvcInterface(如@sebdooe 已经指出的那样),因此这里是具有拦截器的 SpringBoot (2.1.4) 应用程序的最小工作示例:

Minimal.java:

最小的.java:

@SpringBootApplication
public class Minimal
{
    public static void main(String[] args)
    {
        SpringApplication.run(Minimal.class, args);
    }
}

MinimalController.java:

最小控制器.java:

@RestController
@RequestMapping("/")
public class Controller
{
    @GetMapping("/")
    @ResponseBody
    public ResponseEntity<String> getMinimal()
    {
        System.out.println("MINIMAL: GETMINIMAL()");

        return new ResponseEntity<String>("returnstring", HttpStatus.OK);
    }
}

Config.java:

配置文件:

@Configuration
public class Config implements WebMvcConfigurer
{
    //@Autowired
    //MinimalInterceptor minimalInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(new MinimalInterceptor());
    }
}

MinimalInterceptor.java:

MinimalInterceptor.java:

public class MinimalInterceptor extends HandlerInterceptorAdapter
{
    @Override
    public boolean preHandle(HttpServletRequest requestServlet, HttpServletResponse responseServlet, Object handler) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR PREHANDLE CALLED");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR POSTHANDLE CALLED");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception
    {
        System.out.println("MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED");
    }
}

works as advertised

像宣传的那样工作

The output will give you something like:

输出会给你类似的东西:

> Task :Minimal.main()

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

2019-04-29 11:53:47.560  INFO 4593 --- [           main] io.minimal.Minimal                       : Starting Minimal on y with PID 4593 (/x/y/z/spring-minimal/build/classes/java/main started by x in /x/y/z/spring-minimal)
2019-04-29 11:53:47.563  INFO 4593 --- [           main] io.minimal.Minimal                       : No active profile set, falling back to default profiles: default
2019-04-29 11:53:48.745  INFO 4593 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-04-29 11:53:48.780  INFO 4593 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-04-29 11:53:48.781  INFO 4593 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-29 11:53:48.892  INFO 4593 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-04-29 11:53:48.893  INFO 4593 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1269 ms
2019-04-29 11:53:49.130  INFO 4593 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-29 11:53:49.375  INFO 4593 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-29 11:53:49.380  INFO 4593 --- [           main] io.minimal.Minimal                       : Started Minimal in 2.525 seconds (JVM running for 2.9)
2019-04-29 11:54:01.267  INFO 4593 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-29 11:54:01.267  INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-04-29 11:54:01.286  INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 19 ms
MINIMAL: INTERCEPTOR PREHANDLE CALLED
MINIMAL: GETMINIMAL()
MINIMAL: INTERCEPTOR POSTHANDLE CALLED
MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED

回答by Sylvester

Below is an implementation I use to intercept each HTTP request before it goes out and the response which comes back. With this implementation, I also have a single point where I can pass any header value with the request.

下面是我用来在每个 HTTP 请求发出和返回之前拦截它的实现。通过这个实现,我还有一个点,我可以通过请求传递任何标头值。

public class HttpInterceptor implements ClientHttpRequestInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public ClientHttpResponse intercept(
        HttpRequest request, byte[] body,
        ClientHttpRequestExecution execution
) throws IOException {
    HttpHeaders headers = request.getHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
    headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
}

private void traceRequest(HttpRequest request, byte[] body) throws IOException {
    logger.info("===========================Request begin======================================");
    logger.info("URI         : {}", request.getURI());
    logger.info("Method      : {}", request.getMethod());
    logger.info("Headers     : {}", request.getHeaders() );
    logger.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
    logger.info("==========================Request end=========================================");
}

private void traceResponse(ClientHttpResponse response) throws IOException {
    logger.info("============================Response begin====================================");
    logger.info("Status code  : {}", response.getStatusCode());
    logger.info("Status text  : {}", response.getStatusText());
    logger.info("Headers      : {}", response.getHeaders());
    logger.info("=======================Response end===========================================");
}}

Below is the Rest Template Bean

下面是 Rest 模板 Bean

@Bean
public RestTemplate restTemplate(HttpClient httpClient)
{
    HttpComponentsClientHttpRequestFactory requestFactory =
            new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    RestTemplate restTemplate=  new RestTemplate(requestFactory);
    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
    if (CollectionUtils.isEmpty(interceptors))
    {
        interceptors = new ArrayList<>();
    }
    interceptors.add(new HttpInterceptor());
    restTemplate.setInterceptors(interceptors);

    return restTemplate;
}