Skip to content

Commit

Permalink
Ignore response body in eureka client on 404 error.
Browse files Browse the repository at this point in the history
This allows heartbeats to proceed as normal.

Fixes gh-4145
  • Loading branch information
spencergibb committed Mar 4, 2023
1 parent 0dca493 commit 9cea0eb
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,8 +46,11 @@

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;
Expand Down Expand Up @@ -113,7 +118,9 @@ private String stripUserInfo(String serviceUrl) {
}

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);
Expand All @@ -132,13 +139,15 @@ private RestTemplate restTemplate(String serviceUrl) {
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;
}

/**
Expand Down Expand Up @@ -172,11 +181,6 @@ public static BeanSerializerModifier createJsonSerializerModifier() {
@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);
}
Expand All @@ -189,6 +193,50 @@ public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescri
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
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;
Expand Down Expand Up @@ -151,6 +152,12 @@ private ExchangeFilterFunction http4XxErrorExchangeFilterFunction() {
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);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
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;
Expand Down Expand Up @@ -48,8 +49,9 @@ void testCancel() {

@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
Expand All @@ -58,6 +60,12 @@ void testSendHeartBeatFourOFour() {
.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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ public ResponseEntity sendHeartBeat(@PathVariable String appName, @PathVariable
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);
Expand Down

0 comments on commit 9cea0eb

Please sign in to comment.