Follow 302 redirect using Spring restTemplate?
Asked Answered
S

5

32
  RestTemplate restTemplate = new RestTemplate();

  final MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
  final List<MediaType> supportedMediaTypes = new LinkedList<MediaType>(converter.getSupportedMediaTypes());
  supportedMediaTypes.add(MediaType.ALL);
  converter.setSupportedMediaTypes(supportedMediaTypes);
  restTemplate.getMessageConverters().add(converter);  


  ResponseEntity<MyDTO[]> response = restTemplate.getForEntity(urlBase, MyDTO[].class);

  HttpHeaders headers = response.getHeaders();
  URI location = headers.getLocation(); // Has my redirect URI

  response.getBody(); //Always null

I was under the impression that a 302 would automatically be followed. Am I incorrect in this assumption? I now need to pick off this location and re-request?

Squall answered 2/4, 2015 at 17:9 Comment(1)
did u find the answerMesseigneurs
M
27

Using the default ClientHttpRequestFactory implementation - which is the SimpleClientHttpRequestFactory - the default behaviour is to follow the URL of the location header (for responses with status codes 3xx) - but only if the initial request was a GETrequest.

Details can be found in this class - searching for the following method:

protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {

    ...

    if ("GET".equals(httpMethod)) {
        connection.setInstanceFollowRedirects(true);
    }

Here the relevant doc comment of HttpURLConnection.setInstanceFollowRedirects method:

Sets whether HTTP redirects (requests with response code 3xx) should be automatically followed by this {@code HttpURLConnection} instance.

The default value comes from followRedirects, which defaults to true.

Manipur answered 2/4, 2015 at 19:44 Comment(4)
Provided that I am using getForEntity it would be assumed a GET request. I went ahead and ensured the use of the SimpleClientHttpRequestFactory in the restTemplate with only the same result. Going to step into the code you highlighted and see what is happening.Squall
Because your response contains the location header - it tells you that the redirect did not happen. Otherwise the response would contain the result of the very last response received. The only thing could be that the response status is not a 3xx - the location header is ignored. Check the response status code (response.getStatusCode()) first.Manipur
I did new RestTemplate(new SimpleClientHttpRequestFactory() { protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { super.prepareConnection(connection, httpMethod); connection.setInstanceFollowRedirects(false); } }); to disable redirectionButterbur
It follows only one redirectBiestings
R
12

Are you trying to redirect from one protocol to another, e.g. from http to https or vise versa? If so the automatic redirect won't work. See this comment: URLConnection Doesn't Follow Redirect

After discussion among Java Networking engineers, it is felt that we shouldn't automatically follow redirect from one protocol to another, for instance, from http to https and vise versa, doing so may have serious security consequences

from https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4620571

Otherwise if you debug the RestTemplate code you will see that by default HttpURLConnection is set properly with getInstanceFollowRedirects() == true.

Riga answered 18/1, 2019 at 11:12 Comment(1)
SimpleClientHttpRequestFactory: connection.setInstanceFollowRedirects("GET".equals(httpMethod));Provence
D
2

When using the CommonsClientHttpRequestFactory (which uses HttpClient v3 underneath) you can override the postProcessCommonsHttpMethod method and set to follow redirects.

public class FollowRedirectsCommonsClientHttpRequestFactory extends CommonsClientHttpRequestFactory {

  @Override
  protected void postProcessCommonsHttpMethod(HttpMethodBase httpMethod) {
    httpMethod.setFollowRedirects(true);
  }
}

You can then use it like this (with optional, possibly preconfigured, HttpClient instance) and requests will follow the location headers in response:

RestTemplate restTemplate = new RestTemplate(
      new FollowRedirectsCommonsClientHttpRequestFactory());
Dingle answered 7/3, 2017 at 14:45 Comment(0)
P
1

If RestTemplate is Spring Bean and created by RestTemplateBuilder:

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        final var timeout = Duration.ofSeconds(5);
        return builder
                .requestFactory(() -> new SimpleClientHttpRequestFactory() {
                    @Override
                    protected void prepareConnection(HttpURLConnection connection,
                                                     String httpMethod) throws IOException {
                        super.prepareConnection(connection, httpMethod);
                        // always follow redirect for any request method
                        connection.setInstanceFollowRedirects(true);
                    }
                })
                .setConnectTimeout(timeout)
                .setReadTimeout(timeout)
                .build();
    }
Provence answered 25/3, 2024 at 20:9 Comment(0)
O
-5

Try create RestTemplate like this (Spring config):

@Bean("smartRestTemplate")
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder
            .setConnectTimeout(Duration.ofSeconds(..))
            .setReadTimeout(Duration.ofSeconds(..))
            .build();
}
Oshinski answered 16/10, 2021 at 9:57 Comment(2)
This answer would be very much improved by explaining why this might work where the other approach doesn't.Corrupt
It just helps me. But I've also be gratitude for explanation.Oshinski

© 2022 - 2025 — McMap. All rights reserved.