Search code examples
javaspringspring-bootmicroservicesopenfeign

How to add dynamic header values to feign-client through Feign interceptor from current request?


I am new to Spring-cloud-openfeign. I am trying to build a micro-service based system. To make things look simpler, just take 3 of those services, which are Gateway, Service-A, Service-B. When I make a request from my frontend to Service-A through Gateway, the gateway will verify the JWT token in the request, and extract user information (userId) from the token and will put in the request as a header and will forward it to Service-A. Now Service-A will call service-B through feign-client. Now during this inter-service call through feign-client, I am trying to forward userId from the current request in Serice-A to outgoing request to service-B through a Feign RequestIterceptor. But I am not able to retrieve current request in the interceptor. I tried the solution in this stack_over_question, but it doesn't seem to work. I think I face the same problem as of this github_issue. I could see some blogs and articles advising to use RequestContextListner or RequestContextFilter to get the current request out of the Dispatcher-Servlet, But I couldn't find out how to use or implement it. Following is the code I am currently using

@Component
public class ProxyInterceptor implements RequestInterceptor {
        
        
        private final static Logger LOGGER = LoggerFactory.getLogger(ProxyInterceptor.class);
        
        @Override
        public void apply(RequestTemplate requestTemplate) {
                
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                        .getRequest();
                
                String userId = request.getHeader("userId");
                LOGGER.info("userId {}", userId);
                
                if (Optional.ofNullable(userId).isPresent()) {
                        requestTemplate.header(USER_ID_REQUEST_HEADER_VARIABLE, userId);
                }
        }
}

Dependecies

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
            <groupId>org.springframework.cloud</groupId>                     
            <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

<spring-cloud.version>Hoxton.SR8</spring-cloud.version>

This code throws a NullPointer exception as RequestContextHolder.getRequestAttributes() return null. Any idea how to solve this problem?


Solution

  • I had similar use case where I need to get header in the interceptor. The code is similar to below.

    circuitBreakerFactory
                        .create("createUserProfile").run(
                                () -> {
                                        String resp = callerClient.callExternalService();
                                        return resp;
                                        
                                }, exception -> {
                                        logger.info(exception.getMessage());
                                }
                        );
    

    The issue was that the first parameter in the run method is a lambda function and therefore creates a new thread. This new thread does not have request context information of the previous thread that handled the request.

    Add the following bean to the configuration and then the new thread will have request context inherited. Therefore the RequestContextHolder.getRequestAttributes() will not return null.

       @Bean
       DispatcherServlet dispatcherServlet() {
           DispatcherServlet servlet = new DispatcherServlet();
           servlet.setThreadContextInheritable(true);
           return servlet;
       }
    

    You can refer to this answer which helped me a lot.