简体   繁体   English

RestTemplate拦截器

[英]RestTemplate Interceptor

I'm currently trying to incorporate a HandlerInterceptorAdapter but it's not getting registered and comparing it to other answers is tough because everyone is using something different. 我目前正在尝试合并一个HandlerInterceptorAdapter但它没有注册,并且将其与其他答案进行比较很难,因为每个人都在使用不同的东西。 And I'm aware WebMvcConfigureAdapter is deprecated, some versioning is beyond my control for the scope of the project, see usage specs below. 我知道WebMvcConfigureAdapter已被弃用,某些版本控制超出了我对项目范围的控制,请参阅下面的使用规范。

Can someone please provide some guidance on incorporating interceptors with a RestTemplate (that's not ClientHttpRequestInterceptor). 有人可以提供一些关于将拦截器与RestTemplate(不是ClientHttpRequestInterceptor)合并的指导。

Main: 主要:

@SpringBootApplication
@EnableRetry
public class Application extends SpringBootServletInitializer {

  public static void main(String[] args) {

   ApplicationContext ctx = SpringApplication.run(Application.class, args);

  }


  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {

    return applicationBuilder.sources(Application.class);

  }

  @Bean
  private RestTemplate restTemplate(){
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("redacted", 8080));

    SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
    simpleClientHttpRequestFactory.setProxy(proxy);
    simpleClientHttpRequestFactory.setOutputStreaming(false);

    RestTemplate template = new RestTemplate();
    template.setErrorHandler(new MyResponseErrorHandler());

    return template;
  }
}

Interceptor : com.example.foo.config.request.interceptor 拦截器:com.example.foo.config.request.interceptor

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("INTERCEPTED");
    return super.preHandle(request, response, handler);
  }
}

InterceptorConfig : com.example.foo.config.request.interceptor InterceptorConfig:com.example.foo.config.request.interceptor

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter  {

  @Bean
  MyInterceptor myInterceptor() {
    return new MyInterceptor();
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    super.addInterceptors(registry);
    System.out.println("Adding interceptor");
    registry.addInterceptor(myInterceptor());
  }

}

"Adding interceptor" does get logged so I know the configs are being scanned. “添加拦截器”确实被记录,因此我知道正在扫描配置。 I just can't get any interceptor logic to log. 我只是无法获取任何拦截器逻辑来记录。

Using: 使用:

  • Spring Boot v1.5.15 Spring Boot v1.5.15
  • Spring Version: 4.3.18.RELEASE 春季版:4.3.18.RELEASE

HandlerInterceptorAdapter is an implementation that applies to @Controller or @RestController . HandlerInterceptorAdapter是一个适用于@Controller@RestController Not an implementation for RestTemplete . 不是RestTemplete的实现。

To apply it to RestTemplete , you need to use ClientHttpRequestInterceptor . 要将其应用于RestTemplete ,您需要使用ClientHttpRequestInterceptor

ex. 恩。

@Component
public class CustomInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // ... 
    }
}
@Configuation
public class RestTempleteConfig {

    // ...
    @Autowired
    private CustomInterceptor customInterceptor;

    @Bean
    public RestTemplate restTemplate(){
        RestTemplate template = new RestTemplate();
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        template.add(customInterceptor);
        return template;
    }
}

RestTemplate expects ClientHttpRequestInterceptor RestTemplate需要ClientHttpRequestInterceptor

 setInterceptors(List<ClientHttpRequestInterceptor> interceptors) 

Set the request interceptors that this accessor should use. 设置此访问者应使用的请求拦截器。

You can use Servlet Filter to "intercept" requests/response, 您可以使用Servlet过滤器 “拦截”请求/响应,

 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; 

implement this with a servlet filter. 用servlet过滤器实现这个。 No Spring involved here at all 这里根本没有春天

But you will have to change RestTemplate to using other framework as jersey 但是你必须将RestTemplate改为使用其他框架作为泽西

Jersey gives a very handy implementation of such as filter called LoggingFilter which can help in logging all kinds of incoming and outgoing traffic. Jersey提供了一个非常方便的实现,例如名为LoggingFilter的过滤器,它可以帮助记录各种传入和传出流量。

As @WonChulHeo noted you can't use HandlerInterceptorAdapter with RestTemplate . 正如@WonChulHeo所指出的,你不能将HandlerInterceptorAdapterRestTemplate一起RestTemplate Only ClientHttpRequestInterceptor . 只有ClientHttpRequestInterceptor It's not clear why do you need exactly HandlerInterceptorAdapter - we can only see that you are trying to log the fact of the request interception. 目前尚不清楚为什么你需要完全HandlerInterceptorAdapter - 我们只能看到你正在尝试记录请求拦截的事实。 And ClientHttpRequestInterceptor is absolutely able to do the same and even more - check my working example bellow. ClientHttpRequestInterceptor绝对能够做到同样甚至更多 - 请查看我的工作示例。

PS There is an error in your code - you can't use private access for @Bean methods - check your private RestTemplate restTemplate() { please... PS您的代码中存在错误 - 您无法对@Bean方法使用private访问 - 请检查您的private RestTemplate restTemplate() { please ...

@Slf4j
@RestController
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class)
                .bannerMode(Banner.Mode.OFF)
                .run(args);
    }

    @GetMapping("/users/{id}")
    public User get(@PathVariable int id) {
        log.info("[i] Controller: received request GET /users/{}", id);
        return new User(id, "John Smith");
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder templateBuilder) {
        ClientHttpRequestFactory requestFactory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
        return templateBuilder
                .interceptors((request, bytes, execution) -> {
                    URI uri = request.getURI();
                    HttpMethod method = request.getMethod();

                    log.info("[i] Interceptor: requested {} {}", method, uri);
                    log.info("[i] Interceptor: request headers {}", request.getHeaders());

                    ClientHttpRequest delegate = requestFactory.createRequest(uri, method);
                    request.getHeaders().forEach((header, values) -> delegate.getHeaders().put(header, values));

                    ClientHttpResponse response = delegate.execute();
                    log.info("[i] Interceptor: response status: {}", response.getStatusCode().name());
                    log.info("[i] Interceptor: response headers: {}", response.getHeaders());
                    String body = StreamUtils.copyToString(response.getBody(), Charset.defaultCharset());
                    log.info("[i] Interceptor: response body: '{}'", body);

                    return response;
                })
                .rootUri("http://localhost:8080")
                .build();
    }

    @Bean
    ApplicationRunner run(RestTemplate restTemplate) {
        return args -> {
            ResponseEntity<User> response = restTemplate.getForEntity("/users/{id}", User.class, 1);
            if (response.getStatusCode().is2xxSuccessful()) {
                log.info("[i] User: {}", response.getBody());
            } else {
                log.error("[!] Error: {}", response.getStatusCode());
            }
        };
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
}

The HandlerInterceptorAdapter is for the server side (ie RestController) to intercept some important events when server processes a HTTP request , it is nothing to do with what HTTP client (eg RestTemplate ) is used. HandlerInterceptorAdapter用于服务器端(即RestController)在服务器处理HTTP请求时拦截一些重要事件,它与使用什么HTTP客户端(例如RestTemplateRestTemplate

If you want to use RestTemplate as a HTTP client and want to intercept the request just before it sent out and the response just after it received , you must use ClientHttpRequestInterceptor . 如果要将RestTemplate用作HTTP客户端,并希望在发出请求之前拦截请求,并在收到响应之后立即拦截,则必须使用ClientHttpRequestInterceptor

I'm trying to intercept requests and responses in a more flexible way than ClientHttpRequestInterceptor. 我试图以比ClientHttpRequestInterceptor更灵活的方式拦截请求和响应。

From your comment above , what is your actual use-cases that it cannot handle ? 从您上面的评论中,您无法处理的实际用例是什么? I think ClientHttpRequestInterceptor is already quite flexible enough to implement any complex logic to intercept request and response. 我认为ClientHttpRequestInterceptor已经足够灵活,可以实现任何复杂的逻辑来拦截请求和响应。 As your question does not provide any information about how you need to intercept , I can only give a general example to show what the ClientHttpRequestInterceptor can offer . 由于您的问题没有提供有关如何拦截的任何信息,我只能举一个例子来说明ClientHttpRequestInterceptor可以提供什么。

To configure the RestTemplate to use an interceptor : 要配置RestTemplate以使用拦截器:

RestTemplate rt = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors= new ArrayList<ClientHttpRequestInterceptor>();
inteceptors.add(new MyClientHttpRequestInterceptor());

And the ClientHttpRequestInterceptor looks like: ClientHttpRequestInterceptor看起来像:

public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor{

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        //The HTTP request and its body are intercepted here which you can log them or modify them. e.g.
        System.out.println("Log the HTTP request header: " + request.getHeaders());

        //Modify the HTTP request header....
        request.getHeaders().add("foo", "fooValue");

        //Throw exception if you do not want to send the HTTP request

        //If it is at the end of the interceptor chain , call execution.execute() to confirm sending the HTTP request will return the response in ClientHttpResponse
        //Otherwise, it will pass the request to the next interceptor in the chain to process
        ClientHttpResponse response= execution.execute(request, body);

        //The HTTP response is intercepted here which you can log them or modify them.e.g.
        System.out.println("Log the HTTP response header: " + response.getHeaders());

        //Modify the HTTP response header
        response.getHeaders().add("bar", "barValue");

        return response;
    }
}

Please note that you can also configure a chain of ClientHttpRequestInterceptor which allows to split some complex request and response intercept logic into many smalls and reusable ClientHttpRequestInterceptor . 请注意,您还可以配置ClientHttpRequestInterceptor链,该链允许将一些复杂的请求和响应拦截逻辑拆分为许多ClientHttpRequestInterceptor和可重用的ClientHttpRequestInterceptor It is designed with the Chain of responsibility design pattern which its API experience is very similar to what Filter#doFilter() in Servlet . 它采用责任链设计模式设计,其API体验与Servlet Filter#doFilter()非常相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM