Hello.

I'm creating a bean with an ErrorDecoder to implement a custom retry policy. I also have a Retryer bean.

My error decoder:

  @Bean
  public ErrorDecoder errorDecoder(OAuth2ClientContext oAuth2ClientContext) {
    Default errorDecoder = new Default();

    return (methodKey, response) -> {
      FeignException exception = FeignException.errorStatus(methodKey, response);

      if (<custom-check>) {
        return new RetryableException(
            response.status(),
            response.reason(),
            response.request().httpMethod(),
            exception,
            null,
            response.request());
      }

      return errorDecoder.decode(methodKey, response);
    };
  }

My retryer:

  @Bean("customFeignRetrier")
  public Retryer retryer() {
    return new Retryer.Default(this.period, this.maxPeriod, this.retriesLimit);
  }

Making a simple integration test to check the custom policy, when I force the first request to fail, the second throws this exception:

Caused by: java.lang.IllegalArgumentException: url values must be not be absolute.
    at feign.RequestTemplate.uri(RequestTemplate.java:434)
    at feign.RequestTemplate.uri(RequestTemplate.java:421)
    at mypackage.UrlEncodingInterceptor.apply(UrlEncodingInterceptor.java:14)
    at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:161)
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110)
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)

My feign client used in the test case:

@FeignClient(contextId = "Check", name = "check", url = "http://localhost:${server.port}")
public interface ClientCredentialsFeignClient {
  @GetMapping("/check")
  ResponseEntity<SecurityData> check();
}

My test case:

void test() {
    this.wireMockServer.stubFor(
        WireMock.get(WireMock.urlEqualTo("/check"))
            .willReturn(WireMock.aResponse().withStatus(401)));

    Assertions.assertThrows(FeignException.class, () -> this.client.check());

    // verify a mock I have to check if the request was retried
}

Debugging the test execution, the exception is thrown because of another custom interceptor my team are using:

/** Interceptor to fix url encoding of issue: https://github.com/OpenFeign/feign/issues/1190 */
public class UrlEncodingInterceptor implements RequestInterceptor {

  @SneakyThrows
  @Override
  public void apply(RequestTemplate template) {
    template.uri(URLDecoder.decode(template.path(), "UTF-8"));
  }
}

In the first request the template.path() appears to be only the path (/check in this case).. In the second request it is also returning the full URL of the request (http://localhost:1234/check in this case).

Why template.path() returns different values for each execution? Any workaround on this?

Versions:

spring-cloud-starter-openfeign - 3.1.1 (tried to update to 3.1.3 but same error)
feign-core - 11.8
spring-boot - 2.6.6
spring-cloud - 2021.0.1

Comment From: OlgaMaciaszek

Hello @lucasoares, please provide a minimal, complete, verifiable example that reproduces the issue. Preferably as a small GH project with an executable class/ tests that reproduce the issue, not as code snippets that require additional setup on our part.

Comment From: spring-cloud-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-cloud-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Comment From: YuryKorovko

@lucasoares Hi, did you solve that issue ?

Comment From: lucasoares

@lucasoares Hi, did you solve that issue ?

Well, not exactly..

I added the following check in the UrlEncodingInterceptor my team was using:

/** Interceptor to fix url encoding of issue: https://github.com/OpenFeign/feign/issues/1190 */
public class UrlEncodingInterceptor implements RequestInterceptor {

  @SneakyThrows
  @Override
  public void apply(RequestTemplate template) {
    // this if
    if (template.path().startsWith("http") || !template.path().startsWith("/")) {
      return;
    }

    template.uri(URLDecoder.decode(template.path(), StandardCharsets.UTF_8));
  }
}

So it will not break in the second execution.