Espen Schulstad
Espen Schulstad

Reputation: 2445

How can I disable Spring RestTemplate following a HTTP redirect response?

I'm integrating with an ancient service that is adds jsessionid to the URL and redirects to it. I'm using RestTemplate to talk to the service.

The problem is that it follows the redirect forever, since I'm not setting the jsession cookie.

How do I turn off following the redirects in Spring RestTemplate?

Upvotes: 8

Views: 10918

Answers (3)

Ondra Žižka
Ondra Žižka

Reputation: 46796

Adding my solution as I found the others above not fitting the current Spring 5.x and Spring Boot 2.7.

The important aspect is that Spring can be configured with around 6 different HTTP client libraries. The way to configure them differs, and is done by using the client lib's API directly.

Below is an example for Apache HttpClient (historically called HttpCompoments) used to create a RestTemplate for a test. The syntax is Kotlin.

import org.apache.http.client.HttpClient
import org.apache.http.impl.client.HttpClients
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate

@Bean @Qualifier("forTests")
fun restTemplateHttpsWithTestTrustStore(builder: RestTemplateBuilder): RestTemplate {

    val httpClient: HttpClient = HttpClients.custom()
        .disableRedirectHandling()
        .build()

    return builder.requestFactory { HttpComponentsClientHttpRequestFactory(httpClient) }.build()
}

And then the test:

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
)
class HttpsWorksTest {

    @LocalServerPort private var port = 0
    @Autowired @Qualifier("forTests") private lateinit var restTemplateTrustStore: RestTemplate

    @Test
    fun httpsSelfRequestTest() {
        var url = "$proto://localhost:$port/someRediirectingEndpoint"
        log.info("Requesting: GET $url")

        var response = restTemplateTrustStore.getForEntity(url, String::class.java)
        Assertions.assertThat(response.statusCode).isEqualTo(HttpStatus.SEE_OTHER)
    }

}

Upvotes: 1

Espen Schulstad
Espen Schulstad

Reputation: 2445

I figured out one way to do it, don't know if this is the preferred way to do it.

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    final HttpComponentsClientHttpRequestFactory factory = 
             new HttpComponentsClientHttpRequestFactory();
    CloseableHttpClient build = 
             HttpClientBuilder.create().disableRedirectHandling().build();
    factory.setHttpClient(build);
    restTemplate.setRequestFactory(factory);
    return restTemplate;
}

Upvotes: 16

lukascode
lukascode

Reputation: 148

You can also write your own HttpRequestFactory class and override the default behaviour:

class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        super.prepareConnection(connection, httpMethod);
        connection.setInstanceFollowRedirects(false);
    }
}

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate httpClient(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(10))
                .setReadTimeout(Duration.ofSeconds(10))
                .requestFactory(CustomClientHttpRequestFactory.class)
                .build();
    }

}

Upvotes: 2

Related Questions