1

I am trying to call a RESTfull web service resource, this resource is provided by a third party, the resource is exposed with OPTIONS http verb.

To integrate with the service, I should send a request with a specific body, which identities by a provider, but when I did that I got a bad request. After that I trace my code then I recognized that the body of the request is ignored by rest template based on the below code:

if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
            "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
        connection.setDoOutput(true);
    }
    else {
        connection.setDoOutput(false);
    }

my question, is there a standard way to override this behavior or I should use another tool?

AmjadD
  • 73
  • 1
  • 9

1 Answers1

1

The code you've pasted is from

SimpleClientHttpRequestFactory.prepareConnection(HttpURLConnection connection, String httpMethod)

I know because I've debugged that code few hours ago. I had to do a HTTP GET with body using restTemplate. So I've extend SimpleClientHttpRequestFactory, override prepareConnection and create a new RestTemplate using the new factory.

public class SimpleClientHttpRequestWithGetBodyFactory extends SimpleClientHttpRequestFactory {

@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
    super.prepareConnection(connection, httpMethod);
    if ("GET".equals(httpMethod)) {
        connection.setDoOutput(true);
    }
}

}

Create a new RestTemplate based on this factory

new RestTemplate(new SimpleClientHttpRequestWithGetBodyFactory());

A test to prove the solution is working using spring boot (@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT))

public class TestRestTemplateTests extends AbstractIntegrationTests {

@Test
public void testMethod() {
    RestTemplate restTemplate = new RestTemplate(new SimpleClientHttpRequestWithBodyForGetFactory());

    HttpEntity<String> requestEntity = new HttpEntity<>("expected body");

    ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:18181/test", HttpMethod.GET, requestEntity, String.class);
    assertThat(responseEntity.getBody()).isEqualTo(requestEntity.getBody());
}

@Controller("/test")
static class TestController {

    @RequestMapping
    public @ResponseBody  String testMethod(HttpServletRequest request) throws IOException {
        return request.getReader().readLine();
    }
}

}

Florin Grozea
  • 436
  • 4
  • 6
  • I've retested the same derived SimpleClientHttpRequestWithGetBodyFactory with connection.setDoOutput(true) for httpMethod = OPTIONS. The rest template is throwing: org.springframework.web.client.ResourceAccessException: I/O error on OPTIONS request for "http://localhost:18181/test": HTTP method OPTIONS doesn't support output; nested exception is java.net.ProtocolException: HTTP method OPTIONS doesn't support output. So this is the reason why Options have connection.setDoOutput(false); – Florin Grozea Oct 07 '16 at 21:01
  • The GET request I try to send this way become a POST with this solution, I don't know why ... – Benjamin Lucidarme Nov 07 '22 at 11:08