위의 글을 Spring 애플리케이션에서 Feign Client로 여러 마이크로서비스 간의 통신하는 방법에 대한 글입니다.
Feign Client 사용법을 알고 있다는 전제하에, Configuration 설정 및 사용방법에 대해 작성해 보겠습니다.
마이크로서비스 간의 통신을 할 때 각 Feign에 공통적으로 설정해야 할 Header 값이 있을 수 있습니다.
공통 Header 값을 모든 Feign에 설정해 줄 수 있지만, 코드 중복과 가독성을 위해 Feign Client의 Configuration에 커스텀 설정 파일을 지정함으로써 코드 효율을 높일 수 있습니다.
1. Feign에 직접 Header 값 설정하기
@FeignClient(name = "user-service", url = "http://localhost:8080")
public interface UserClient {
@GetMapping("/users/1", headers = "header1=value1")
UserDTO find();
@GetMapping("/users/1", headers = {"header1=value1", "header2=value2"})
UserDTO find2();
}
- header가 1개일 경우에는 headers = name=value 형식으로 작성할 수 있습니다.
- 여러 개인 경우 배열로 작성합니다.
2. 모든 Feign에 공통적인 Header 값 설정하기
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> requestTemplate.header("header", "tokenValue");
}
}
- FeignConfig 클래스는 공통적인 요소를 설정할 Configuration 파일입니다.
- RequestInterceptor 인터페이스를 구현하여, Feign Client의 요청을 보내기 전에 호출되어 수정을 할 수 있습니다.
(여기서 수정이란 공통적인 Header 값을 설정하는 것을 의미합니다.) - 람다 표현식을 사용해 requestInterceptor() 메서드는 apply() 메서드를 오버라이드 합니다.
- RequestTemplate 객체의 header() 메서드를 사용하여 요청에 Header를 추가합니다.
- "header1"은 해당 Header의 Key이며, "tokenValue"는 value를 의미하며 key-value 설정을 통해 Header에 원하는 값들을 설정합니다.
@FeignClient에 커스텀 설정파일 주입하기
@FeignClient(name = "user-service", url = "http://localhost:8080", configuration = FeignConfig.class)
public interface UserClient {
@GetMapping("/users/1")
UserDTO find();
}
Header에 있는 AccessToken을 모든 Feign header에 담아서 전달하기
트러블슈팅
이슈
👉 auth-service와 통신을 통해 사용자 정보를 불러와야 했다.
"/members"에 요청을 보내기 위해서 header에 Authorization: Bearer **** 처럼 JWT 토큰을 담아서 전달해야 했고, 모든 Feign에 적용하기 위해서 Configuration을 통해 header에 값을 추가하는 로직을 구현해야 했다.
문제
👉 HttpServletRequest만 사용해봐 요청 중인 Http 통신에서 설정된 header 값을 어떻게 파싱 하는지 몰랐다.
현재 연결된 Http 요청의 속성을 사용할 수 있는 방법을 찾아보며 코드에 적용해보며 header 값이 제대로 설정되는지 확인해 보았다.
해결
👉 여러 자료를 찾아보면서 현재 스레드에 연결된 Http 요청을 얻기 위해서 아래의 객체들을 이용하여 문제를 해결할 수 있었다.
1. RequestContextHolder : Spring에서 제공하는 유틸리티 클래스로, 현재 스레드에 연결된 요청을 관리합니다.
2. getRequestAttributes()를 통해 RequestContextHolder 객체에서 연결된 요청 속성을 가져옵니다. 이 메서드를 통해 RequestAttributes를 반환합니다.
3. ServletRequestAttributes은 RequestAttributes 인터페이스를 구현한 클래스로, Http 요청과 관련된 속성에 쉽게 접근할 수 있는 클래스입니다. 자료형 변환을 통해 쉽게 다룰 수 있는 클래스 형태로 변경합니다.
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String accessToken = request.getHeader("Authorization");
if (authorizationHeader != null) {
requestTemplate.header("Authorization", accessToken);
}
}
};
}
- ServletRequestAttributes 객체에 getRequest()를 통해 HttpServletRequest를 가져옵니다.
- HttpServletRequest는 웹 애플리케이션에서 클라이언트로부터 들어오는 Http 요청에 대해 정보를 제공합니다.
- getHeader("headerKey")를 통해 원하는 header의 값을 가져올 수 있습니다.
원하는 AccessToken을 얻은 이후에는, 똑같이 requestTemplate.header("Authorization", acessToken) 코드를 통해 값을 설정합니다.
'Spring Framework > Spring Cloud' 카테고리의 다른 글
[Spring Gateway] Spring Cloud Gateway Cors 설정하기 - MSA 환경Cors 설정 방법 (0) | 2024.05.09 |
---|---|
[Spring Cloud] Spring Cloud에서 OpenFeign 사용하기: RESTful 서비스 간 통신 방법 (0) | 2024.04.08 |