8
votes

I have a number of clients for which a "global" RequestInterceptor has been defined. For one of the clients I need this "global" interceptor to be excluded. Is it possible to override the full set of RequestInterceptors for a particular FeignClient?

@FeignClient(value = "foo", configuration = FooClientConfig.class)
public interface FooClient {
//operations
}

@Configuration
public class FooClientConfig{

//How do I exclude global interceptors from this client configuration?
}

The spring-cloud-netflix version in use is 1.1.0 M5

2
That's an interesting question. My first guess is that you might have to extend a Feign.Builder that ignores any call to requestInterceptors or ignores the ones you want. - spencergibb
@spencergibb In other words, for a given client, I want to override any existing interceptors using a custom client config. This is surprisingly difficult. - Newbie
It will difficult for me to maintain the list of interceptors that I don't want included in this client. Therefore, I'm not going to register global interceptors at all. Instead, every single client is going to be declared with an specific configuration attached to it. In my case, this means that I will have 2 custom feign client configurations, one for most clients and another for exceptional/one-off client. :-( - Newbie
It is because you can have multiple interceptors and the feign application contexts inherit from the parent. Maybe an option to NOT inherit from the parent on @FeignClient? - spencergibb
That's a good workaround - spencergibb

2 Answers

2
votes

It seems there is no easy way to override the global interceptor. I think you could do it like this:

@Configuration
public class FooClientConfig{

@Bean
RequestInterceptor globalRequestInterceptor() {
    return template -> {
        if (template.url().equals("/your_specific_url")) {
            //don't add global header for the specific url
            return;
        }

        //add header for the rest of requests
        template.header(AUTHORIZATION, String.format("Bearer %s", token));
    };
}
}
0
votes

An enhanced way of solving this is to pass a custom header to your request like:

@PostMapping("post-path")
ResponseEntity<Void> postRequest(@RequestHeader(HEADER_CLIENT_NAME) String feignClientName, @RequestBody RequestBody requestBody);

I want to set the header in interceptor for only this feign client. Before setting the header, first, the interceptor checks HEADER_CLIENT_NAME header if exists and have the desired value:

private boolean criteriaMatches(RequestTemplate requestTemplate) {
    Map<String, Collection<String>> headers = requestTemplate.headers();
    return headers.containsKey(HEADER_CLIENT_NAME)
        && headers.get(HEADER_CLIENT_NAME).contains("feign-client-name");
}

Thus, you can check before setting the basic authentication. In interceptor:

@Override
public void apply(RequestTemplate template) {
    if (criteriaMatches(template)) {
        /*apply auth header*/
    }
}

In this way, other feign client's requests won't be manipulated by this interceptor.

Finally, I set the feignClientName to the request:

feignClient.postRequest("feign-client-name", postBody);