Apache HttpClient 중간 오류: NoHttpResponseException
XML을 웹 이 웹 서비스는 하고 있으며, 임의의 XML을 을 송신하는 할 수 . 정상적으로 작동하다가 임의의 경우 메시지와 함께 IOException을 보내는 서버와 통신할 수 없습니다.The target server failed to respond이후의 콜은 정상적으로 동작합니다.
대부분의 경우, 전화를 걸어 애플리케이션을 10~15분간 아이돌 상태로 두면 발생합니다.그 후 처음 걸었을 때 이 오류가 반환됩니다.
몇 가지 시도를 해봤는데...
리트라이 핸들러를 다음과 같이 설정합니다.
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) {
if (retryCount >= 3){
Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block");
return false;
}
if (e instanceof org.apache.http.NoHttpResponseException){
Logger.warn(CALLER, "No response from server on "+retryCount+" call");
return true;
}
return false;
}
};
httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);
하지만 이 재시도는 호출되지 않았습니다.(예, 올바른 절 인스턴스를 사용하고 있습니다).디버깅 중 이 클래스는 호출되지 않습니다.
HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false);지만소소 소소소다다지금 내가 뭘 할 수 있는지 누가 제안해줄래?
중요 왜 예외를 인정받는지 알아내는 것 외에 제가 안고 있는 중요한 고민 중 하나는 왜 리트라이 핸들러가 여기서 일하지 않는가 하는 것입니다.
대부분의 경우 연결 매니저에 의해 활성 상태로 유지되는 영구 연결은 오래된 연결이 됩니다.즉, 접속이 아이돌 상태일 때 HttpClient가 해당 이벤트에 반응할 수 없는 상태에서 타깃서버가 접속을 셧다운하여 접속이 반닫히거나 '스톨' 상태가 됩니다.보통 이것은 문제가 되지 않습니다.HttpClient는 풀에서 리스할 때 연결 유효성을 확인하기 위해 몇 가지 기술을 사용합니다.오래된 접속 체크가 디세블로 되어 있고 오래된 접속을 사용하여 요청 메시지가 전송되어도 보통 SocketException을 사용한 쓰기 조작에서는 요청 실행이 실패하고 자동으로 재시도됩니다.그러나 상황에 따라 쓰기 작업이 예외 없이 종료될 수 있으며 이후 읽기 작업은 -1(스트림 끝)을 반환합니다.이 경우 HttpClient는 요청이 성공했다고 가정할 수밖에 없지만 서버 측에서 예기치 않은 오류가 발생하여 서버가 응답하지 못했을 가능성이 높습니다.
이 상황을 해결하는 가장 간단한 방법은 비활성 상태가 일정 기간 지속된 후 예를 들어 1분 이상 아이돌 상태가 된 연결 및 연결을 풀에서 제거하는 것입니다.자세한 내용은 HttpClient 튜토리얼의 이 섹션을 참조하십시오.
인정된 답변은 맞지만 해결책이 부족하다.이 오류를 방지하려면 이 답변과 같이 HTTP 클라이언트에 setHttpRequestRetryHandler(또는 아파치컴포넌트 4.4의 경우 setRetryHandler)를 추가합니다.
HttpClient 4.4는 요청자에게 돌아가기 전에 오래된 접속을 검증하는 것과 관련된 이 영역의 버그로 인해 어려움을 겪었습니다.연결이 오래되었는지 여부를 검증하지 않았기 때문에 즉시 연결이 끊어집니다.NoHttpResponseException.
이 문제는 HttpClient 4.4.1에서 해결되었습니다.이 JIRA 및 릴리스 노트를 참조하십시오.
현재 대부분의 HTTP 접속은 특별히 선언되지 않는 한 영속적인 것으로 간주됩니다.단, 서버 자원을 절약하기 위해 접속을 영원히 열어 두는 경우는 거의 없습니다.예를 들어 Apache httpd 2.2 이상에서는 많은 서버의 기본 접속 타임아웃이 5초 정도로 짧습니다.
org.apache.http.NoHttpResponseException에러는 서버에 의해 닫힌1개의 영속적인 접속에서 발생할 가능성이 높습니다.
Apache Http 클라이언트 풀에서 사용되지 않는 연결을 열어 두는 최대 시간(밀리초)을 설정할 수 있습니다.
Spring Boot을 사용하여 이를 실현하는 방법 중 하나는 다음과 같습니다.
public class RestTemplateCustomizers {
static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpClient httpClient = HttpClientBuilder
.create()
.setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS)
.build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
}
// In your service that uses a RestTemplate
public MyRestService(RestTemplateBuilder builder ) {
restTemplate = builder
.customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer())
.build();
}
인정된 답변은 맞지만 IMHO는 회피책일 뿐입니다.
확실히 하자면, 영속적인 접속이 끊어지는 것은 지극히 정상적인 상황입니다.그러나 HTTP 클라이언트라이브러리가 올바르게 처리할 수 없는 경우는 매우 안 좋습니다.
Apache Http Client의 이 장애 동작은 오랫동안 수정되지 않았기 때문에 OkHttp와 같은 오래된 연결 문제에서 쉽게 복구할 수 있는 라이브러리로 전환하는 것이 좋습니다.
왜요?
- OkHttp는 기본적으로 http 연결을 풀링합니다.
- 가 아니기 때문에 요구를 할 수 됩니다.http는 POST). HttpClient(Apache HttpClient)에 수 .
NoHttpResponseException를 참조해 주세요. - 초기 초안 및 베타 버전에서 HTTP/2.0을 지원합니다.
했을 때 OkHttp에 문제가 .NoHttpResponseException영원히 사라졌어요
솔루션: Reuse Strategy를 never로 변경
이 문제는 매우 복잡하고 실패할 수 있는 여러 가지 요인이 있기 때문에 저는 다음 게시물에서 이 해결책을 찾을 수 있어서 기뻤습니다.org.apache.http 해결 방법NoHttpResponseException
연결을 재사용하지 마십시오. org.apache.http.impl.client에서 설정합니다.AbstractHttp Client:
httpClient.setReuseStrategy(new NoConnectionReuseStrategy());
org.apache.http.impl.client에서도 같은 설정을 할 수 있습니다.HttpClientBuilder 빌더:
builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
이 문제는 만약disableContentCompression()는 HttpClient에 할당된 풀링 매니저로 설정되어 타겟서버가 gzip 압축을 사용하려고 합니다.
Apache http 클라이언트 4.5.5에서 기본 헤더를 추가하는 경우에도 동일한 문제가 발생함
연결: 닫기
문제를 해결하다
사용하다PoolingHttpClientConnectionManager대신BasicHttpClientConnectionManager
BasicHttpClientConnectionManager는 같은 루트를 가진 후속 요구에 접속을 재사용하려고 합니다.단, 기존 연결을 닫고 지정된 경로에 대해 연결을 다시 엽니다.
저도 같은 문제에 직면해 있습니다.확장기능으로 "connection: close"를 추가하여 해결했습니다.
순서 1: 새로운 클래스 Connection Close Extension을 만듭니다.
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.http.HttpHeader;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;
public class ConnectionCloseExtension extends ResponseTransformer {
@Override
public Response transform(Request request, Response response, FileSource files, Parameters parameters) {
return Response.Builder
.like(response)
.headers(HttpHeaders.copyOf(response.getHeaders())
.plus(new HttpHeader("Connection", "Close")))
.build();
}
@Override
public String getName() {
return "ConnectionCloseExtension";
}
}
순서 2: 다음과 같이 wireMockServer에서 확장 클래스를 설정합니다.
final WireMockServer wireMockServer = new WireMockServer(options()
.extensions(ConnectionCloseExtension.class)
.port(httpPort));
언급URL : https://stackoverflow.com/questions/10558791/apache-httpclient-interim-error-nohttpresponseexception
'source' 카테고리의 다른 글
| Spring Boot 응용 프로그램에 컨텍스트 경로 추가 (0) | 2022.11.24 |
|---|---|
| mysql mariadb 부모와 일치하는 검색 (0) | 2022.11.24 |
| 배열이 있는 응답에서 Axios 응답 데이터 가져오기 (0) | 2022.11.22 |
| 변환 VueJ를 사용하여 상태를 변경하시겠습니까? (0) | 2022.11.22 |
| java.io 를 참조해 주세요.Eclipse IDE의 콘솔 지원 (0) | 2022.11.22 |