| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- LinkedList
- actuator
- JPA
- 백엔드공부
- 백엔드
- 컴퓨터 공학
- SpringBoot
- TestCode
- 자료구조
- ORM
- 서버
- Java
- spring boot
- QueryDSL
- JWT
- 프로그래머스
- 핵심가이드
- 제로베이스
- queue
- 백엔드스쿨
- spring
- 스프링부트
- 개발자
- 백준
- SpringSecurity
- 연관관계
- array
- restTemplate
- error
- 컴퓨터 구조
- Today
- Total
be_better
[Springboot] 서버 간 통신 - WebClient 본문
목차
WebClient 란?
Spring WebFlux는 HTTP 요청을 수행하는 클라이언트로 WebClient를 제공한다. WebClient는 리액터(Reactor) 기반으로 동작하는 API이다. 리액터 기반이므로 스레드와 동시성 문제를 벗어나 비동기 형식으로 사용될 수 있다.
WebClient 특징들
- 논블로킹(Non-Blocking) I/O를 지원한다.
- 리액티브 스트림(Reactive Streams)의 백 프레셔(Back Pressure)를 지원한다.
- 적은 하드웨어 리소스로 동시성을 지원한다.
- 함수형 API를 지원한다.
- 동기, 비동기 상호작용을 지원한다.
- 스트리밍을 지원한다.
WebClient 구성
WebClient를 사용하려면 WebFlux 모듈에 대한 의존성을 추가해야 한다.
WebFlux 의존성 추가
// gradle
implementation 'org.springframework.boot:spring-boot-starter-webflux'
// maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
WebClient 사용하기
WebClient 구현
WebClient를 생성하는 방법은 크게 두 가지가 있다.
- create() 메서드를 이용한 생성
- builder()를 이용한 생성
WebClient GET 예제
WebClient를 활용한 GET 요청 예제
@Service
public class WebClientService {
public String getName() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
return webClient.get()
.uri("/api/v1/crud-api")
.retrieve()
.bodyToMono(String.class)
.block();
}
public String getNameWithPathVariable() {
WebClient webClient = WebClient.create("http://localhost:9090");
ResponseEntity<String> responseEntity = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}")
.build("Jnjeaaaat"))
.retrieve()
.toEntity(String.class)
.block();
return responseEntity.getBody();
}
public String getNameWithParameter() {
WebClient webClient = WebClient.create("http://localhost:9090");
return webClient.get().uri(uriBuilder -> uriBuilder.path("api/v1/crud-api")
.queryParam("name", "Jnjeaaaat")
.build())
.exchangeToMono(clientResponse -> {
if (clientResponse.statusCode().equals(HttpStatus.OK)) {
return clientResponse.bodyToMono(String.class)
} else {
return clientResponse.createException().flatMap(Mono::error);
}
})
.block();
}
}
getName() 메서드는 builder()를 활용해 WebClient를 만들고
다른 두 개의 메서드에서는 create()를 활용해 WebClient를 생성한다.
WebClient는 우선 객체를 생성한 후 요청을 전달하는 방식으로 동작한다. builder()를 통해 baseUrl() 메서드에서 기본 URL을 설정하고 defaultHeader() 메서드로 헤더의 값을 설정했다. 일반적으로 WebClient 객체를 이용할 때는 이처럼 WebCllient 객체를 생성한 후 재사용하는 방식으로 구현하는 것이 좋다.
builder()를 사용할 경우 확장할 수 있는 메서드 리스트
- defaultHeader(): WebClient의 기본 헤더 설정
- defaultCookie(): WebClient의 기본 쿠키 설정
- defaultUriVariable(): WebClient의 기본 URI 확장값 설정
- filter(): WebClient에서 발생하는 요청에 대한 필터 설정
이미 빌드된 WebClient는 변경할 수 없지만 복사해서는 사용할 수 있다.
WebClient 복제
WebClient webClient = WebClient.create("http://localhost:9090");
WebClient clone = webClient.mutate().build();
WebClient는 HTTP 메서드를 get(), post(), put(), delete() 등의 네이밍이 명확한 메서드로 설정할 수 있다. 그리고 URI를 확장하는 방법으로 uri() 메서드를 사용할 수 있다.
retrieve() 메서드는 요청에 대한 응답을 받았을 때 그 값을 추출하는 방법. retrieve() 메서드는 bodyToMono() 메서드를 통해 리턴 타입을 설정해서 문자열 객체를 받아온다.
이때 Mono는 Flux와 비교되는 개념으로 Flux와 Mono는 리액티브 스트림에서 데이터를 제공하는 발행자 역할을 수행하는 Publisher의 구현체이다.
WebClient는 기본적으로 논블로킹(Non-Blocking) 방식으로 동작하기 때문에 기존에 사용하던 코드의 구조를 블로킹 구조로 바꿔줄 필요가 있기 때문에 block()이라는 메서드를 추가해 블로킹 형식으로 동작하게끔 설정한다.
코드에서 getNameWithPathVariable() 메서드 내부에서 uriBuilder를 사용해 path를 설정하고 build() 메서드에 추가할 값을 넣는 것으로 pathVariable을 추가하는 방식으로 구현했지만 간략하게 작성하고 싶다면 다음 코드로 변경해도 좋다.
// 변경 전
ResponseEntity<String> responseEntity = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}")
.build("Jnjeaaaat"))
.retrieve()
.toEntity(String.class)
.block();
// 변경 후
ResponseEntity<String> responseEntity = webClient.get()
.uri("/api/v1/crud-api/{name}", "Jnjeaaaat")
.retrieve()
.toEntity(String.class)
.block();
이때 toEntity() 를 사용하면 ResponseEntity 타입으로 응답을 전달받을 수 있다.
WebClient POST 예제
WebClient를 활용한 POST 요청 예제
@Service
public class WebClientService {
public ResponseEntity<MemberDto> postWithParamAndBody() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("Jnjeaaaat");
memberDto.setEmail("ekswn120@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient.post().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "Jnjeaaaat")
.queryParam("email", "ekswn120@gmail.com")
.queryParam("organization", "Free")
.build())
.bodyValue(memberDto)
.retrieve()
.toEntity(MemberDto.class)
.block();
}
public ResponseEntity<MemberDto> postWithHeader() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("Jnjeaaaat");
memberDto.setEmail("ekswn120@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient
.post()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/add-header")
.build())
.bodyValue(memberDto)
.header("my-header", "Wikibooks API")
.retrieve()
.toEntity(MemberDto.class)
.block();
}
}
POST 방식에서는 bodyValue() 메서드를 통해 HTTP 바디 값을 설정하고
header() 메서드를 통해 헤더에 값을 추가한다.
'Springboot > 이론' 카테고리의 다른 글
| [Springboot] Spring Security 필터 동작 (0) | 2023.12.06 |
|---|---|
| [Springboot] 서비스의 인증과 권한 부여 - SpringSecurity 소개 (0) | 2023.12.06 |
| [Springboot] 서버 간 통신 - RestTemplate 사용해보기 (0) | 2023.11.29 |
| [Springboot] 서버 간 통신 - RestTemplate 소개 (0) | 2023.11.29 |
| [Springboot] 액추에이터 활용하기 - 커스텀 (0) | 2023.11.29 |