Ignore response body in eureka client on 404 error.

This allows heartbeats to proceed as normal.

Fixes gh-4145
This commit is contained in:
spencergibb
2023-03-04 00:18:13 -05:00
parent 0dca49318c
commit 9cea0ebe23
4 changed files with 82 additions and 14 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.netflix.eureka.http;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Optional;
@@ -44,8 +46,11 @@ import com.netflix.discovery.shared.transport.TransportClientFactory;
import org.springframework.cloud.configuration.SSLContextFactory;
import org.springframework.cloud.configuration.TlsProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
@@ -113,7 +118,9 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
}
private RestTemplate restTemplate(String serviceUrl) {
RestTemplate restTemplate = restTemplate();
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
RestTemplate restTemplate = new RestTemplate(requestFactory);
try {
URI serviceURI = new URI(serviceUrl);
@@ -132,13 +139,15 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
restTemplate.setErrorHandler(new ErrorHandler());
return restTemplate;
}
restTemplate.getInterceptors().add((request, body, execution) -> {
ClientHttpResponse response = execution.execute(request, body);
if (!response.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
return response;
}
return new NotFoundHttpResponse(response);
});
private RestTemplate restTemplate() {
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
return new RestTemplate(requestFactory);
return restTemplate;
}
/**
@@ -172,11 +181,6 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
JsonSerializer<?> serializer) {
/*
* if (beanDesc.getBeanClass().isAssignableFrom(Applications.class)) {
* return new ApplicationsJsonBeanSerializer((BeanSerializerBase)
* serializer, keyFormatter); }
*/
if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
return new InstanceInfoJsonBeanSerializer((BeanSerializerBase) serializer, false);
}
@@ -189,6 +193,50 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
public void shutdown() {
}
/**
* Response that ignores body, specifically for 404 errors.
*/
private static class NotFoundHttpResponse implements ClientHttpResponse {
private final ClientHttpResponse response;
NotFoundHttpResponse(ClientHttpResponse response) {
this.response = response;
}
@Override
public HttpStatusCode getStatusCode() throws IOException {
return response.getStatusCode();
}
@Override
public int getRawStatusCode() throws IOException {
return response.getRawStatusCode();
}
@Override
public String getStatusText() throws IOException {
return response.getStatusText();
}
@Override
public void close() {
response.close();
}
@Override
public InputStream getBody() throws IOException {
// ignore body on 404 for heartbeat, see gh-4145
return null;
}
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
}
}
class ErrorHandler extends DefaultResponseErrorHandler {
@Override

View File

@@ -38,6 +38,7 @@ import com.netflix.discovery.shared.Applications;
import com.netflix.discovery.shared.resolver.EurekaEndpoint;
import com.netflix.discovery.shared.transport.EurekaHttpClient;
import com.netflix.discovery.shared.transport.TransportClientFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
@@ -151,6 +152,12 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
newResponse.body((clientHttpResponse, context) -> clientHttpResponse.getBody());
return Mono.just(newResponse);
}
if (clientResponse.statusCode().equals(HttpStatus.NOT_FOUND)) {
ClientResponse newResponse = clientResponse.mutate().statusCode(clientResponse.statusCode())
// ignore body on 404 for heartbeat, see gh-4145
.body(Flux.empty()).build();
return Mono.just(newResponse);
}
return Mono.just(clientResponse);
});
}

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.eureka.http;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.shared.Applications;
import com.netflix.discovery.shared.transport.EurekaHttpClient;
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
@@ -48,8 +49,9 @@ abstract class AbstractEurekaHttpClientTests {
@Test
void testSendHeartBeat() {
assertThat(eurekaHttpClient.sendHeartBeat("test", "test", info, null).getStatusCode())
.isEqualTo(HttpStatus.OK.value());
EurekaHttpResponse<InstanceInfo> response = eurekaHttpClient.sendHeartBeat("test", "test", info, null);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK.value());
assertThat(response.getEntity()).isNotNull();
}
@Test
@@ -58,6 +60,12 @@ abstract class AbstractEurekaHttpClientTests {
.isEqualTo(HttpStatus.NOT_FOUND.value());
}
@Test
void testSendHeartBeatFourOFourWithBody() {
assertThat(eurekaHttpClient.sendHeartBeat("fourOFourWithBody", "test", info, null).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND.value());
}
@Test
void testStatusUpdate() {
assertThat(eurekaHttpClient.statusUpdate("test", "test", InstanceInfo.InstanceStatus.UP, info).getStatusCode())

View File

@@ -118,6 +118,11 @@ public class EurekaServerMockApplication {
if ("fourOFour".equals(appName)) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
if ("fourOFourWithBody".equals(appName)) {
return new ResponseEntity(
"{ \"error\": \"Not Found\", \"message\": null, \"path\": \"/1\", \"requestId\": \"9e5d3244-1\", \"status\": 404, \"timestamp\": \"2023-03-04T03:31:20.810+00:00\" }",
HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(new InstanceInfo(null, null, null, null, null, null, null, null, null, null, null,
null, null, 0, null, null, null, null, null, null, null, new HashMap<>(), 0L, 0L, null, null),
HttpStatus.OK);