open api 사용방법 찾아보기
webclient 사용방법
1. webClient 개발
1) api 작성
webclientController 라는 이름으로 api 작성
@RestController
public class WebClientController {
@GetMapping("/test")
public Mono<String> doTest() {
WebClient client = WebClient.create();
return client.get()
.uri("http://localhost:5011/webclient/test-create")
.retrieve()
.bodyToMono(String.class);
}
}
가장 기본적인 webclient 사용 예제
webClient.create()는 빠르게 테스트 할 때 사용,
실제로는 webClient.builder()를 이용하여 여러가지 옵션을 부여해 사용
1개의 값을 리턴할 때는 bodyToMono 사용
복수의 값을 리턴 할 때는 bodyToFlux 사용
2) 실행, 테스트
Terminal을 열고 webserver 프로젝트 디렉토리로 이동
/mvnw clean package -DskipTests && java -jar target/webclient.jar
이 명령어로 실행jar를 생성 후 실행
curl 명령으로 webserver를 호출 해 결과가 정상적으로 나오는지 확인
❯ curl -i http://localhost:5001/test
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 39
test-create => Working successfully !!!
@GetMapping("/test2")
public Mono<String> doTest2() {
HttpClient httpClient = HttpClient.create()
.tcpConfiguration(
client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) //miliseconds
.doOnConnected(
conn -> conn.addHandlerLast(new ReadTimeoutHandler(5)) //sec
.addHandlerLast(new WriteTimeoutHandler(60)) //sec
)
);
WebClient client = WebClient.builder()
.baseUrl("http://localhost:5011")
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
return client.get()
.uri("/webclient/test-builder")
.retrieve()
.bodyToMono(String.class);
}
2) baseUrl
위 예시처럼 baseUrl에 Host를 지정하고, uri에는 Path만 지정해 사용할 수 있음
3) filter
filter를 이용하여 Request, Response를 컨트롤 할 수 있음
doTest2 메소드에 filter를 추가하기
첫번째 필터에는 Request Header를 추가하고,
두번째 필터에는 Request Header를 로깅하고,
세번째 필터에는 Response Header를 로깅한다
@RestController
public class WebClientController {
private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(getClass());
...
@GetMapping("/test2")
public Mono<String> doTest2() {
...
WebClient client = WebClient.builder()
.baseUrl("http://localhost:5011")
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter(
(req, next) -> next.exchange(
ClientRequest.from(req).header("from", "webclient").build()
)
)
.filter(
ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
log.info(">>>>>>>>>> REQUEST <<<<<<<<<<");
log.info("Request: {} {}", clientRequest.method(), clientRequest.url());
clientRequest.headers().forEach(
(name, values) -> values.forEach(value -> log.info("{} : {}", name, value))
);
return Mono.just(clientRequest);
}
)
)
.filter(
ExchangeFilterFunction.ofResponseProcessor(
clientResponse -> {
log.info(">>>>>>>>>> RESPONSE <<<<<<<<<<");
clientResponse.headers().asHttpHeaders().forEach((name, values) -> values.forEach(value -> log.info("{} : {}", name, value)));
return Mono.just(clientResponse);
}
)
)
.build();
...
}
}
webClient 콘솔 로그를 확인하기
webServer의 콘솔 로그 확인, Request Header에 'from'이 있는지 확인하기
4) buff memory 늘리기
Request Data를 버퍼링 하기 위한 메모리의 기본값은 256KB 인데,
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer
만약 이런 에러가 발생한다면 버퍼 메모리를 늘려주어야 한다
ExchangeStrategies로 메모리를 지정하고 webClient.exchangeStragegies로 적용
@GetMapping("/test2")
public Mono<String> doTest2() {
...
//Memory 조정: 2M (default 256KB)
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2*1024*1024))
.build();
WebClient client = WebClient.builder()
...
.exchangeStrategies(exchangeStrategies)
.build();
...
}
5) Spring Bean class 이용(defaultHeader, defaultCookie 포함)
webClient를 만드는데에 시간이 걸리니까 미리 만들어놓고 사용하는 방법을 사용하기도 한다
이 webClient를 사용하는 모든 수행에서 공통 HttpRequest Header 와 공통 Cookie가 있다면 defaultHeader와 defaultCookie를 이용
@Configuration
public class WebClientConfig {
private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(getClass());
@Bean
public WebClient webClient() {
HttpClient httpClient = HttpClient.create()
.tcpConfiguration(
client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) //miliseconds
.doOnConnected(
conn -> conn.addHandlerLast(new ReadTimeoutHandler(5)) //sec
.addHandlerLast(new WriteTimeoutHandler(60)) //sec
)
);
//Memory 조정: 2M (default 256KB)
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2*1024*1024))
.build();
return WebClient.builder()
.baseUrl("http://localhost:5011")
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter(
(req, next) -> next.exchange(
ClientRequest.from(req).header("from", "webclient").build()
)
)
.filter(
ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
log.info(">>>>>>>>>> REQUEST <<<<<<<<<<");
log.info("Request: {} {}", clientRequest.method(), clientRequest.url());
clientRequest.headers().forEach(
(name, values) -> values.forEach(value -> log.info("{} : {}", name, value))
);
return Mono.just(clientRequest);
}
)
)
.filter(
ExchangeFilterFunction.ofResponseProcessor(
clientResponse -> {
log.info(">>>>>>>>>> RESPONSE <<<<<<<<<<");
clientResponse.headers().asHttpHeaders().forEach((name, values) -> values.forEach(value -> log.info("{} : {}", name, value)));
return Mono.just(clientResponse);
}
)
)
.exchangeStrategies(exchangeStrategies)
.defaultHeader("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.3")
.defaultCookie("httpclient-type", "webclient")
.build();
}
}
그 다음 webClientController.java를 아래처럼 단순하게 만들고
@Autowired 주석을 지정하고 webClient를 정의하면 미리 만들어진 webClient를 사용할 수 있다
@RestController
public class WebClientController {
private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(getClass());
@Autowired
private WebClient webClient;
@GetMapping("/test")
public Mono<String> doTest() {
WebClient client = WebClient.create();
return client.get()
.uri("http://localhost:5011/webclient/test-create")
.retrieve()
.bodyToMono(String.class);
}
@GetMapping("/test2")
public Mono<String> doTest2() {
return webClient.get()
.uri("/webclient/test-builder")
.retrieve()
.bodyToMono(String.class);
}
}
그 다음 webClient를 빌드, 실행, 테스트 하고
webClient와 webServer의 콘솔 확인
6) mutate
webClientConfig에서 지정되어있는 baseUrl(Target host)이 다를 경우 사용할 수 없다는 점을 보완하고자 사용하는 것이 mutate
webConfigController에 메소드 추가
@GetMapping("/test3")
public Mono<String> doTest3() {
return webClient
.mutate()
.baseUrl("http://localhost:5011")
.build()
.get()
.uri("/webclient/test-mutate")
.retrieve()
.bodyToMono(String.class);
}
WebClient와 webServer의 콘솔에서 bean으로 생성한 webClient에 적용한 모든 옵션이 동작하는 것을 확인 할 수 있음