Spring Framework’s RestTemplate
provides simple ways to make requests to RESTful services. When you want to set additional HTTP headers to such requests, then a tiny bit of more work is needed.
Starting from Spring Framework version 3.0.2 it is possible to utilise HttpEntity
class. An example of querying a PDF file from a server:
private static final String APPLICATION_PDF = "application/pdf"; RestTemplate restTemplate = new RestTemplate(); @Test public void acceptHeaderUsingHttpEntity() throws Exception { HttpHeaders headers = new HttpHeaders(); headers.setAccept(singletonList(MediaType.valueOf(APPLICATION_PDF))); ResponseEntity<byte[]> response = restTemplate.exchange("http://example.com/file/123", GET, new HttpEntity<byte[]>(headers), byte[].class); String responseText = PdfTextExtractor.getTextFromPage(new PdfReader(response.getBody()), 1); assertEquals("Some text in PDF file", responseText); }
(I’m using iText here for PDF file manipulation.)
Starting from Spring Framework version 3.1 there is a more powerful alternative — ClientHttpRequestInterceptor
. ClientHttpRequestInterceptor.intercept()
enables more control over the HTTP request that will be sent. Here’s the simple example again, using the interceptor concept:
private static final String APPLICATION_PDF = "application/pdf"; RestTemplate restTemplate = new RestTemplate(); @Test public void acceptHeaderUsingHttpRequestInterceptors() throws Exception { ClientHttpRequestInterceptor acceptHeaderPdf = new AcceptHeaderHttpRequestInterceptor( APPLICATION_PDF); restTemplate.setInterceptors(singletonList(acceptHeaderPdf)); byte[] response = restTemplate.getForObject("http://example.com/file/123", byte[].class); String responseText = PdfTextExtractor.getTextFromPage(new PdfReader(response), 1); assertEquals("Some text in PDF file", responseText); } class AcceptHeaderHttpRequestInterceptor implements ClientHttpRequestInterceptor { private final String headerValue; public AcceptHeaderHttpRequestInterceptor(String headerValue) { this.headerValue = headerValue; } @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request); requestWrapper.getHeaders().setAccept(singletonList(MediaType.valueOf(headerValue))); return execution.execute(requestWrapper, body); } }
This is awesome! thanks for the code. I am running into a problem with using exchange() on spring 3.0.6 where HttpMethod.DELETE is not allowed to have a body. I have tried many many configurations, and every time my handler functions get an empty ” @RequestBody String bodyData “. Do you think I could use this Interceptor to add a body when using a delete? Or possibly start off with POST and then rewrite to DELETE so that the body is preserved!? I understand that this requires an upgrade to 3.1. Thanks so much for this article!
RestTemplate by default uses Spring’s own SimpleClientHttpRequestFactory. This factory creates requests with such settings, that HTTP body is supported by POST and PUT methods only. Forcing SimpleClientHttpRequestFactory to use HTTP body in case of DELETE method won’t work, because JDK’s HttpURLConnection does not enable this (you would get an IOException during runtime if you try that).
Switching RestTemplate’s request factory simply to Apache HTTPClient’s HttpComponentsClientHttpRequestFactory unfortunately won’t help either, because HttpDelete does not support HttpEntity, unlike HttpPost and HttpPut.
So it seems JDK and Apache HttpClient HTTP request factories work the same way. I’m afraid using an interceptor won’t improve things in this case either.
Interestingly, HTTP RFC does not forbid using HTTP body with DELETE. See also http://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request for more information about this.
With some level of hacking (YMMV), it is possible to make RestTemplate handle HTTP body for DELETE requests. For this, you need to create a custom request factory that is able to create a custom implementation for DELETE method requests. Something like this:
The test:
The server/controller under test:
Sven,
Thank you so much for posting this! I almost feel like this could be it’s own blog post. I haven’t tried this yet, but I will check it out very soon and get back to you. I am using this code as part of a unit test for my own REST api, but I can live without this test for now.
It’s annoying to learn that Java (and others!) don’t allow a body for DELETE even tho the HTTP RCF allows it. I really appreciate you spending the time to respond to me. Great blog keep it up!
Thanks, Benjamin! 🙂
Great Post Sven! I just based my integration tests on this post, it was exactly what I was looking for. Thank you so much for posting it!!!
Great Post. Helped me a lot, Thanks!!!
Thank you Sven. I knew there was a better way to set headers. Thanks!!!!
Thanks
Perfect post….. helped me a lot!
Very helpful! Thanks!
hi,
I have a query . I want to send some string values as well as pdf’s byte array . Can i do that in one call ? if yes how to achive that ?
Not entirely sure what you want to do. Do you want to send a POST/PUT request with essentially multiple objects (strings and a PDF)? If so, the request body should be a container or envelope of some sort I suppose. In regard to what HTTP headers should be sent along the message, it really depends on what the server expects.
Reblogged this on S.F.F.S. — Selene Fox Free Spaces and commented:
相当赞的一篇博文,Big Thanks
Do you mind if I quote a few of your posts as long as I provide credit and sources back to your weblog? My blog is in the very same niche as yours and my users would truly benefit from a lot of the information you present here. Please let me know if this alright with you. Thank you! feekdeeeeecd
Alright. What is the location of your blog?
I must say thanks – this saved me a lot of time!
I was searching on “Spring RestTemplate set header”, and the results I get are all like (these ones are among the more useful ones):
– http://stackoverflow.com/questions/19238715/how-to-set-an-accept-header-on-spring-resttemplate-request
– http://stackoverflow.com/questions/11579621/spring-resttemplate-postforobject-with-header-webservice-cant-find-my-header-p
But yes, your one is what I have in mind but didn’t know exists!
We can use it in Spring boot for GET Method in the below manner :
@SpringBootApplication
public class Application implements CommandLineRunner{
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String… args) throws Exception {
try{
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders = this.createHeaders();
ResponseEntity response;
response = restTemplate.exchange(“”,HttpMethod.GET,new HttpEntity(httpHeaders),String.class);
log.info(response.toString());
}
catch(Exception e)
{
System.out.println(“Exception”+e);
}
}
private HttpHeaders createHeaders(){
HttpHeaders headers = new HttpHeaders(){
{
set( “Authorization”, “3ee140”);
}
};
return headers;
}
}