The solution is to use @RequestHeader annotation instead of feign specific annotations
@FeignClient(name="Simple-Gateway")
interface GatewayClient {
@RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
String getSessionId(@RequestHeader("X-Auth-Token") String token);
}
Answer from Hasnain on Stack OverflowThe solution is to use @RequestHeader annotation instead of feign specific annotations
@FeignClient(name="Simple-Gateway")
interface GatewayClient {
@RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
String getSessionId(@RequestHeader("X-Auth-Token") String token);
}
The @RequestHeader did not work for me. What did work was:
@Headers("X-Auth-Token: {access_token}")
@RequestLine("GET /orders/{id}")
Order get(@Param("id") String id, @Param("access_token") String accessToken);
You can also achieve this by adding header to individual methods as follows:
@RequestMapping(method = RequestMethod.GET, path = "/resource", headers = {"myHeader=value"})
Using @Headers with dynamic values in Feign client + Spring Cloud (Brixton RC2) discusses a solution for dynamic values using @RequestHeader.
You can set a specific configuration class on your feign interface and define a RequestInterceptor bean in there. For example:
@FeignClient(name = "foo", url = "http://localhost:4444/feign",
configuration = FeignConfiguration.class)
public interface LocalhostClient {
}
@Configuration
public class FeignConfiguration {
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
// Do what you want to do
}
};
}
}
Yes, you can do that. With Feign, we usually declare our interface with the method returning our class and Feign will automatically de-serialise the response from JSON into our POJO.
Here is the interface (operation):
@FeignClient(name = "library-book-service")
@RequestMapping("books")
public interface BookClient {
@GetMapping
public List<Book> getBooks(
@RequestParam("page") Integer pageNum,
@RequestParam("size") Integer pageSize,
@RequestParam("reader") Long readerId);
}
And then you can use the feign client like this:
@Service
@RequiredArgsConstructor
public class BookService {
private final @NonNull BookClient bookClient;
public List<Book> retrieveBooks(
Integer pageNum,
Integer pageSize,
Long readerId) {
return bookClient.getBooks(pageNum, pageSize, readerId);
}
However, in order to have access to the response headers, you need to declare your methods to return feign.Response.
import feign.Response;
@FeignClient(name = "library-book-service")
@RequestMapping("books")
public interface BookClient {
@GetMapping
public Response getBooks(
@RequestParam("page") Integer pageNum,
@RequestParam("size") Integer pageSize,
@RequestParam("reader") Long readerId);
}
This way you can have access to the response body and headers:
@Service
@RequiredArgsConstructor
public class BookService {
private final @NonNull BookClient bookClient;
private final @NonNull ObjectMapper objectMapper;
public List<Book> retrieveBooks(
Integer pageNum,
Integer pageSize,
Long readerId) {
var response = bookClient.getBooks(pageNum, pageSize, readerId);
if (response == null) {
return Collections.emptyList();
}
// retrieve body
var books = objectMapper.readValue(
new BufferedReader(new InputStreamReader(response.body().asInputStream(), StandardCharsets.UTF_8)),
new TypeReference<List<Book>>(){});
// retrieve headers
Map<String, Collection<String>> headers = response.headers();
// ... do whatever you need with the headers
return books;
}
You can use import feign.Response as a response like:
@PostMapping("/test")
Response test(@RequestBody TestRequest testRequest);
then you can reach http header
response.headers().get(HEADER_NAME).toString();
if you want get body in this case you have to some json-string manipulation by use response.body() this page may help you for this
You can create an interceptor that'd inject headers in all requests as below:
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("user", username);
requestTemplate.header("password", password);
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}
Also it provides a way to set interceptor using property files as below:
feign:
client:
config:
default:
requestInterceptors:
com.baeldung.cloud.openfeign.JSONPlaceHolderInterceptor
we can create the configuration with default as the client name to configure all @FeignClient objects, or we can declare the feign client name for a configuration
Reference: https://www.baeldung.com/spring-cloud-openfeign
EDIT: Another way is to set headers in yml as below:
feign:
client:
config:
default:
defaultRequestHeaders:
Authorization:
- Basic dXNlcjpwYXNzd29yZA==
SomeOtherHeader:
- Value1
- Value2
we have used below for kotlin to make sure we add proper headers to all the request sent :
Feign client with configuration setup
@FeignClient(name = "YourClient", url = "\${base-url}", configuration = [FeignHeaderConfiguration::class])
interface YourClient
Header configuration
@Configuration
class FeignHeaderConfiguration {
@Bean
fun clientHeaderInterceptor(): ClientHeaderInterceptor {
return ClientHeaderInterceptor()
}
}
and interceptor where we added the header
class ClientHeaderInterceptor : RequestInterceptor {
override fun apply(requestTemplate: RequestTemplate) {
requestTemplate.header("Accept", MediaType.APPLICATION_JSON_VALUE)
}
}