it-roy-ru.com

Отправка запроса GET с заголовками аутентификации с помощью restTemplate

Мне нужно получить ресурсы с моего сервера, отправив запрос GET с некоторыми заголовками авторизации, используя RestTemplate.

После просмотра docs я заметил, что ни один из методов GET не принимает заголовки в качестве параметра, и единственный способ отправить заголовки, такие как accept и Authorization, - это использование exchange метод.

Поскольку это очень простое действие, мне интересно, если я что-то упустил, а есть другой, более простой способ сделать это?

63
special0ne

Вы ничего не пропускаете. RestTemplate#exchange(..) - подходящий метод для установки заголовков запросов.

Вот пример (с POST, но просто измените его на GET и используйте желаемую сущность).

Вот еще один пример.

Обратите внимание, что с GET ваша сущность запроса не должна содержать ничего (если ваш API не ожидает этого, но это противоречит спецификации HTTP). Это может быть пустая строка.

56
Sotirios Delimanolis

Вы можете использовать postForObject с HttpEntity. Это будет выглядеть так:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer "+accessToken);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);

В GET-запросе вы обычно не отправляете тело (это разрешено, но это не имеет никакого значения). Чтобы добавить заголовки без разводки RestTemplate по-разному, используйте методы exchange или execute напрямую. Сокращения get не поддерживают модификацию заголовка.

На первый взгляд асимметрия немного странная, возможно, это будет исправлено в будущих версиях Spring.

39
iwein

Вот очень простой пример с базовой аутентификацией, заголовками и обработкой исключений ...

private HttpHeaders createHttpHeaders(String user, String password)
{
    String notEncoded = user + ":" + password;
    String encodedAuth = "Basic " + Base64.getEncoder().encodeToString(notEncoded.getBytes());
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", encodedAuth);
    return headers;
}

private void doYourThing() 
{
    String theUrl = "http://blah.blah.com:8080/rest/api/blah";
    RestTemplate restTemplate = new RestTemplate();
    try {
        HttpHeaders headers = createHttpHeaders("fred","1234");
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
        System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
    }
    catch (Exception eek) {
        System.out.println("** Exception: "+ eek.getMessage());
    }
}
18
Dave

Все эти ответы кажутся неполными и/или кладжами. Если посмотреть на интерфейс RestTemplate, то он наверняка выглядит так, как будто в него было введено ClientHttpRequestFactory, а затем этот requestFactory будет использоваться для создания запроса, включая любые настройки заголовков, тела и параметров запроса.

Либо вам нужно универсальное ClientHttpRequestFactory для внедрения в один общий RestTemplate, либо вам нужно получить новый экземпляр шаблона через new RestTemplate(myHttpRequestFactory).

К сожалению, создание такой фабрики выглядит несколько нетривиально, даже если вы просто хотите установить один заголовок авторизации, что довольно неприятно, если учесть, что является общим требованием, но, по крайней мере, позволяет легко его использовать, например, если ваш заголовок Authorization может быть создан из данных, содержащихся в объекте Authorization Spring-Security, затем вы можете создать фабрику, которая устанавливает исходящий AuthorizationHeader для каждого запроса, выполнив SecurityContextHolder.getContext().getAuthorization(), а затем, при необходимости, заполнив заголовок пустыми проверками. Теперь все исходящие вызовы отдыха, сделанные с помощью RestTemplate, будут иметь правильный заголовок авторизации.

Без особого акцента на механизме HttpClientFactory, обеспечивающем простые для перегрузки базовые классы для общих случаев, таких как добавление одного заголовка к запросам, большинство удобных методов Nice RestTemplate в конечном итоге являются пустой тратой времени, поскольку используемый.

Я хотел бы увидеть что-то простое, как это сделано доступным

@Configuration
public class MyConfig {
  @Bean
  public RestTemplate getRestTemplate() {
    return new RestTemplate(new AbstractHeaderRewritingHttpClientFactory() {
        @Override
        public HttpHeaders modifyHeaders(HttpHeaders headers) {
          headers.addHeader("Authorization", computeAuthString());
          return headers;
        }
        public String computeAuthString() {
          // do something better than this, but you get the idea
          return SecurityContextHolder.getContext().getAuthorization().getCredential();
        }
    });
  }
}

На данный момент интерфейс доступного ClientHttpRequestFactory труднее взаимодействовать, чем этот. Еще лучше было бы использовать абстрактную оболочку для существующих реализаций фабрики, которая делает их похожими на более простой объект, такой как AbstractHeaderRewritingRequestFactory, с целью замены всего лишь одного фрагмента функциональности. Прямо сейчас, они очень общего назначения, так что даже написание этих оберток - сложное исследование.

7
ideasculptor