使用Spring restTemplate如何跟随302重定向?

31
  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

我原来的想法是302状态码会自动跳转,但这个想法是否正确呢?现在我需要获取这个位置并重新请求吗?


1
你找到答案了吗? - Afroz Shaikh
4个回答

25
使用默认的ClientHttpRequestFactory实现 - 这是SimpleClientHttpRequestFactory - 默认行为是跟随位置头的URL(对于响应状态码3xx),但仅在初始请求是GET请求时才这样做。
可以在该类中找到详细信息 - 搜索以下方法:
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {

    ...

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

这里是HttpURLConnection.setInstanceFollowRedirects方法的相关文档注释:

设置是否由此 {@code HttpURLConnection} 实例自动跟随 HTTP 重定向(响应代码为 3xx 的请求)。

默认值来自 followRedirects,默认为 true。


假设我正在使用getForEntity,那么就会默认为GET请求。我已经确保在restTemplate中使用了SimpleClientHttpRequestFactory,但结果仍然相同。我将进入您标记的代码并查看发生了什么。 - techie.brandon
因为您的响应包含 location 标头 - 这告诉您重定向未发生。否则,响应将包含最后一个接收到的响应结果。唯一可能的情况是响应状态不是 3xx - 忽略位置标头。首先检查响应状态码(response.getStatusCode())。 - fateddy
16
我使用了 `new RestTemplate(new SimpleClientHttpRequestFactory() { protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { super.prepareConnection(connection, httpMethod); connection.setInstanceFollowRedirects(false); } });` 来禁用重定向。 - mzzzzb
它仅遵循一个重定向。 - Skeeve

11
你是否想要从一个协议重定向到另一个协议,例如从http到https或反之?如果是的话,自动重定向将不起作用。请参考此评论:URLConnection Doesn't Follow Redirect 引用如下: Java网络工程师经过讨论后认为,我们不应自动跟随从一个协议到另一个协议的重定向,例如从http到https或反之,这样做可能会产生严重的安全后果。
来自https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4620571 否则,如果您调试RestTemplate代码,则默认情况下HttpURLConnection会正确设置为getInstanceFollowRedirects() == true

2
使用CommonsClientHttpRequestFactory(其在底层使用HttpClient v3)时,您可以重写postProcessCommonsHttpMethod方法并设置为跟随重定向。
public class FollowRedirectsCommonsClientHttpRequestFactory extends CommonsClientHttpRequestFactory {

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

您可以像这样使用它(使用可选的、可能预配置过的HttpClient实例),请求将遵循响应中的“location”头:
RestTemplate restTemplate = new RestTemplate(
      new FollowRedirectsCommonsClientHttpRequestFactory());

-4
尝试像这样创建RestTemplate(Spring配置):

@Bean("smartRestTemplate")
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder
            .setConnectTimeout(Duration.ofSeconds(..))
            .setReadTimeout(Duration.ofSeconds(..))
            .build();
}

1
这个答案如果解释一下为什么这种方法可行而另一种方法不行,会更加完善。 - M. Justin
它只是帮助了我。但我也感激解释。 - Grigory Kislin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接