我需要通过使用RestTemplate发送带有一些Authorization标头的GET请求来从我的服务器检索资源。
在浏览了docs之后,我注意到没有一个GET方法接受头作为参数,并且发送Headers(如accept和Authorization)的唯一方法是使用exchange方法。
既然这是一个非常基本的动作,我想知道我是否遗漏了一些东西,还有另一种更简单的方法吗?
你没有遗漏任何东西。 RestTemplate#exchange(..)
是用于设置请求标头的适当方法。
Here's an example(使用POST,但只需将其更改为GET并使用您想要的实体)。
请注意,使用GET,您的请求实体不必包含任何内容(除非您的API期望它,但这将违反HTTP规范)。它可以是一个空字符串。
你可以使用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 shorthands不支持标头修改。
乍一看,这种不对称有点奇怪,也许这将在未来的Spring版本中修复。
这是一个带有基本身份验证,标头和异常处理的超级简单示例......
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());
}
}
所有这些答案似乎都是不完整的和/或kludges。看看RestTemplate接口,它看起来好像是要注入一个ClientHttpRequestFactory
,然后requestFactory将用于创建请求,包括头,正文和请求参数的任何自定义。
你需要一个通用的ClientHttpRequestFactory
注入一个共享的RestTemplate
,否则你需要通过new RestTemplate(myHttpRequestFactory)
获得一个新的模板实例。
不幸的是,创建这样一个工厂看起来有点不重要,即使你只是想设置一个Authorization标头,考虑到可能的常见要求,这是非常令人沮丧的,但至少它允许使用方便,例如,您的Authorization标头可以从Spring-Security Authorization
对象中包含的数据创建,然后您可以通过执行SecurityContextHolder.getContext().getAuthorization()
创建一个工厂,在每个请求上设置传出的AuthorizationHeader,然后填充标头,并进行适当的空检查。现在,使用该RestTemplate进行的所有出站休息调用都将具有正确的授权标头。
在没有更多地强调HttpClientFactory机制的情况下,为常见情况提供简单到重载的基类,例如向请求添加单个头,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,目的是替换这一个功能。现在,它们非常通用,即使编写这些包装也是一项复杂的研究。