将我的自定义HTTP标头添加到Spring RestTemplate请求/扩展RestTemplate

50

我的当前代码:

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Mall[] malls = restTemplate.getForObject(url, Mall[].class);

我需要为我的请求添加一些自定义标头,格式如下:

X-TP-DeviceID : <GUID>

在我的情况下,最简单的方法是什么?是否有任何方式在将请求发送到服务器之前向我的restTemplate对象添加自定义标头定义?

[编辑]

这正确吗?

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

HttpHeaders headers = new HttpHeaders();
headers.set("X-TP-DeviceID", "1234567890");
HttpEntity entity = new HttpEntity(headers);

HttpEntity<Mall[]> response = restTemplate.exchange(url, HttpMethod.GET, entity, Mall[].class);

Mall[] malls = response.getBody();

[添加]

好的,我设法让它起作用了。然而,我对此并不完全满意。在我的情况下,我需要为我所做的所有调用提供相同的自定义标头。

那么,我的下一个问题是 - 是否可能将我的自定义标头设置为在每个 web-service 调用时自动添加,例如通过扩展 RestTemplate 类并将所有自定义标头放在那里?然后,我所需要做的就是简单地使用我的自定义扩展 RestTemplate 代替默认的,所有我的自定义标头都将默认存在。

4个回答

62

您可以通过RestTemplate exchange方法如下来传递自定义的HTTP头。

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(new MediaType[] { MediaType.APPLICATION_JSON }));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("X-TP-DeviceID", "your value");

HttpEntity<RestRequest> entityReq = new HttpEntity<RestRequest>(request, headers);

RestTemplate template = new RestTemplate();

ResponseEntity<RestResponse> respEntity = template
    .exchange("RestSvcUrl", HttpMethod.POST, entityReq, RestResponse.class);

编辑:下面是更新后的代码。这个链接提供了多种调用REST服务的示例

RestTemplate restTemplate = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("X-TP-DeviceID", "your value");

HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

ResponseEntity<Mall[]> respEntity = restTemplate.exchange(url, HttpMethod.POST, entity, Mall[].class);

Mall[] resp = respEntity.getBody();

1
我能否以某种方式检查我的自定义标头是否真的设置了?没有访问服务器日志。它可以工作,我可以成功获取响应,但我不知道我的应用程序是否实际发送了我的自定义标头。 - user1209216
好的,谢谢您的建议。实际上,服务器目前还没有提供任何验证功能。 - user1209216
我更新了我的问题,抱歉取消了“已接受答案”- 我需要更多信息。 - user1209216
2
请澄清HttpEntity ctor中的“parameters”是什么意思。这是一个魔法值(必须完全是这样),还是可以使用某个常量,或者被忽略?提前感谢。 - chrisinmtown
1
哎呀,这太糟糕了。对于使用RestTemplate来说,这几乎是个致命问题。对于Web服务客户端来说,传递一些自定义默认头部非常普遍。 - dustinevan
显示剩余6条评论

44

如果目标是拥有一个可重用的RestTemplate,通常可用于将相同的标题附加到一系列类似请求中,可以使用org.springframework.boot.web.client.RestTemplateCustomizer参数与RestTemplateBuilder

 String accessToken= "<the oauth 2 token>";
 RestTemplate restTemplate = new RestTemplateBuilder(rt-> rt.getInterceptors().add((request, body, execution) -> {
        request.getHeaders().add("Authorization", "Bearer "+accessToken);
        return execution.execute(request, body);
    })).build();

3
不确定为什么这个回答会被踩到负数,因为在我看来它恰恰是正确的。在我将其从RestTemplateBuilder中整理出来后(我的情况下不是一个spring-boot项目),它完美地运行了。 - Filippo Possenti
我想做相同的事情,但是针对POST正文而不是标头。我想在POST urlformencoded负载中发送相同的键值对。有什么想法吗? - Boss Man
@BossMan 在return execution.execute(request, body);之前修改body怎么样? - k_o_
@k_o_,“body”的类型是“byte[]”。我猜我应该说:“有什么高效的方法吗?” - Boss Man
@BossMan:嗯,也许还有其他选项,但为什么不解析正文,将其转换为字符串并附加、过滤、前置任何你想要的内容呢?如果你找到了一个静态模式,你可以预先初始化这些数据并重复使用它。 - k_o_

8
将"User-Agent"标头添加到您的请求中。
一些服务器试图阻止爬虫程序和抓取器访问它们的服务器,因为在较早的日子里,请求没有发送用户代理标头。
你可以尝试设置自定义用户代理值或使用一些标识浏览器的值,如"Mozilla/5.0 Firefox/26.0"。
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();

headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("user-agent", "Mozilla/5.0 Firefox/26.0");
headers.set("user-key", "your-password-123"); // optional - in case you auth in headers
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<Game[]> respEntity = restTemplate.exchange(url, HttpMethod.GET, entity, Game[].class);

logger.info(respEntity.toString());

1
为什么/如何使用“参数”来设置标头是正确的方式? - beauXjames
1
请注意,HttpHeaders#addHttpHeaders#set之间的区别在于前者将添加一个新标头,而后者将覆盖标头(如果已存在)。 - Tim Biegeleisen

2
这里是我编写的检查URL是否存在的方法。我有一个要求需要添加请求头。这是Groovy编写的,但应该很容易适应Java。本质上,我使用了org.springframework.web.client.RestTemplate#execute(java.lang.String, org.springframework.http.HttpMethod, org.springframework.web.client.RequestCallback, org.springframework.web.client.ResponseExtractor<T>, java.lang.Object...) API方法。我猜你得到的解决方案至少部分取决于你想执行的HTTP方法。以下示例的关键是,我传递了一个Groovy闭包(作为方法restTemplate.execute()的第三个参数,更或多或少地说是Java世界中的Lambda),由Spring API作为回调执行,以便在Spring执行命令之前操纵请求对象。
boolean isUrlExists(String url) {
    try {
      return (restTemplate.execute(url, HttpMethod.HEAD,
              { ClientHttpRequest request -> request.headers.add('header-name', 'header-value') },
              { ClientHttpResponse response -> response.headers }) as HttpHeaders)?.get('some-response-header-name')?.contains('some-response-header-value')
    } catch (Exception e) {
      log.warn("Problem checking if $url exists", e)
    }
    false
  }

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