복붙노트

[SPRING] 응답하지 않는 반응하는 WebClient

SPRING

응답하지 않는 반응하는 WebClient

Spring Reactive WebClient에 대한 질문이 있습니다 ... 며칠 전 스프링 프레임 워크에서 새로운 반응 물질을 사용하기로 결심했고 개인적인 목적으로 만 데이터를 긁어 모을 작은 프로젝트를 만들었습니다. (하나의 웹 페이지에 여러 요청을하고 결과를 결합).

나는 요청을 만들기 위해 새로운 반응적인 WebClient를 사용하기 시작했으나 발견 한 문제는 클라이언트가 모든 요청에 ​​대해 응답하지 않는다는 것입니다. 이상하게 들린다. 다음은 데이터를 가져 오기 위해 수행 한 작업입니다.

private Mono<String> fetchData(String uri) {
    return this.client
            .get()
            .uri(uri)
            .header("X-Fsign","SW9D1eZo")
            .retrieve()
            .bodyToMono(String.class)
            .timeout(Duration.ofSeconds(35))
            .log("category", Level.ALL, SignalType.ON_ERROR, SignalType.ON_COMPLETE, SignalType.CANCEL, SignalType.REQUEST);
}

그리고 fetchData를 호출하는 함수 :

public Mono<List<Stat>> fetch() {
    return fetchData(URL)
            .map(this::extractUrls)
            .doOnNext(System.out::println)
            .doOnNext(s-> System.out.println("all ids are "+s.size()))
            .flatMapIterable(q->q)
            .map(s -> s.substring(7, 15))
            .map(s -> "http://d.flashscore.com/x/feed/d_hh_" + s + "_en_1") // list of N-length urls
            .flatMap(this::fetchData)
            .map(this::extractHeadToHead)
            .collectList();
}

및 가입자 :

    FlashScoreService bean = ctx.getBean(FlashScoreService.class);
    bean.fetch().subscribe(s->{
        System.out.println("finished !!! " + s.size()); //expecting same N-length list size
    },Throwable::printStackTrace);

문제는 제가 100 개 이상의 요청을 더 많이 만들어 본 것입니다.  나는 그들 모두에 대한 응답을 얻지 못했고 에러가 발생하지 않았거나 에러 응답 코드가 리턴되었고 요청 수와 다른 크기로 subscribe 메소드가 호출되었습니다.

내가 만든 요청은 List of Strings (URL)을 기반으로하며 모든 응답이 나온 후에 collectList ()를 사용하기 때문에 목록을 모두 받아야합니다. 100 개의 요청을 실행하면 100 개의 응답 목록을받을 것으로 예상되지만 실제로는 가끔은 100, 때로는 96 등을받습니다. 뭔가 잘못 될 수 있습니다.  여기는 내 github 프로젝트 링크가 쉽게 재현 할 수 있습니다.

샘플 출력 :

all ids are 176
finished !!! 171

디버깅 방법이나 내가 잘못하고있는 것에 대해 제안 해주십시오. 도움을 주시면 감사하겠습니다.

최신 정보:

예를 들어 126 개의 URL을 전달하면 로그에 다음과 같이 표시됩니다.

onNext(ReactorClientHttpResponse{request=[GET/some_url],status=200}) is called 121 times. May be here is the problem.
onComplete() is called 126 times which is the exact same length of the passed list of urls

그러나 onNext () 또는 onError ()를 호출하지 않고 요청 중 일부를 완료 할 수있는 방법은 무엇입니까? (Mono에서의 성공과 오류)

문제는 WebClient가 아니라 다른 곳에서 생각합니다. 환경 또는 서버 요청을 차단하지만 일부 오류 로그를 받아야 할 수도 있습니다.

추신. 도와 주셔서 감사합니다 !

해결법

  1. ==============================

    1.이것은 까다 롭습니다. 실제로받은 HTTP 프레임을 디버깅하면 일부 요청에 대해 응답을 얻지 못하는 것으로 보입니다. Wireshark로 좀 더 디버깅을하면, 원격 서버가 FIN, ACK TCP 패킷으로 연결 종료를 요청하고 클라이언트가 그것을 확인한 것처럼 보입니다. 문제는이 연결이 첫 번째 FIN, ACK TCP 패킷 다음에 다른 GET 요청을 보내기 위해 여전히 풀에서 가져온 것입니다.

    이것은 까다 롭습니다. 실제로받은 HTTP 프레임을 디버깅하면 일부 요청에 대해 응답을 얻지 못하는 것으로 보입니다. Wireshark로 좀 더 디버깅을하면, 원격 서버가 FIN, ACK TCP 패킷으로 연결 종료를 요청하고 클라이언트가 그것을 확인한 것처럼 보입니다. 문제는이 연결이 첫 번째 FIN, ACK TCP 패킷 다음에 다른 GET 요청을 보내기 위해 여전히 풀에서 가져온 것입니다.

    리모트 서버가 여러 요청을 처리 한 후 커넥션을 닫는 것일 수도 있습니다. 어쨌든 그것은 완벽하게 합법적 인 행동입니다. 이것을 일관되게 재현하지는 않습니다.

    클라이언트에서 연결 풀링을 비활성화 할 수 있습니다. 이 속도는 느려지고 분명히이 문제를 유발하지 않습니다. 이를 위해 다음을 사용하십시오.

    this.client = WebClient.builder()
                    .clientConnector(new ReactorClientHttpConnector(new Consumer<HttpClientOptions.Builder>() {
                        @Override
                        public void accept(HttpClientOptions.Builder builder) {
                            builder.disablePool();
                        }
                    }))
                    .build();
    

    근본적인 문제는 응답을 보내지 않고 TCP 연결이 닫힐 때 HTTP 클라이언트가 onComplete해서는 안된다는 것입니다. 또는 HTTP 클라이언트는 연결이 닫히는 동안 연결을 다시 사용하지 않아야합니다. 내가 더 많이 알게되면 여기서 다시보고 할게.

  2. from https://stackoverflow.com/questions/44930448/reactive-webclient-not-emitting-a-response by cc-by-sa and MIT license