restTemplate delete with body

2019-06-03 05:46发布

问题:

I am trying to do DELETE with request body but I keep getting 400 (bad request) error. When I do it in the swagger/postman, it is successfully deleting the record. But from the Java code I can't do that

The external API is designed in a way that it needs body along with URL. It can't be changed. please let me know how can I delete that entry with request body

public Person delete(Person person, String url, Map<String, String> uriVariables) throws JsonProcessingException {
        RestTemplate restTemplate = new RestTemplate();
        CustomObjectMapper mapper = new CustomObjectMapper();
        HttpEntity<Person> requestEntity = new HttpEntity<Person>(person);
        try {
            ResponseEntity<Person> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Person.class, uriVariables);
            return responseEntity.getBody();
        } catch (RestClientException e) {
            System.out.println(mapper.writeValueAsString(person));
            throw e;
        }
    }

when it goes to exception, I will get the JSON request in JSON format and the same works fine in Swagger/postman

I did some googling and found that restTemplate have problem deleting when there is request body. this article wasn't helpful https://jira.spring.io/browse/SPR-12361 is there any way to get it work

回答1:

Issue exists for Spring version 4.0.x or earlier.
In later version it has been fixed.

This might be a late answer, but in one of my project I solved this issue via a custom ClientHttpRequestFactory to RestTemplate

If no factory is provided to RestTemplate, it uses default implementation SimpleClientHttpRequestFactory

In SimpleClientHttpRequestFactory class, DELETE method is not allowed with request body.

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

Just write your own implementation as

import java.io.IOException;
import java.net.HttpURLConnection;

import org.springframework.http.client.SimpleClientHttpRequestFactory;

public class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, 
            String httpMethod) throws IOException {

        super.prepareConnection(connection, httpMethod);
        if("DELETE".equals(httpMethod)) {
            connection.setDoOutput(true);
        }
    }
}

After that create your RestTemplate object as

RestTemplate template = new RestTemplate(
                            new CustomClientHttpRequestFactory());

Fix in later versions of (4.1.x or above) SimpleClientHttpRequestFactory class

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


回答2:

Another way to fix this is to use restTemplate.exchange, here's an example:

try {
      String jsonPayload  = GSON.toJson(request);
      HttpEntity<String> entity = new HttpEntity<String>(jsonPayload.toString(),headers());
      ResponseEntity resp = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class);
} catch (HttpClientErrorException e) {
      /* Handle error */
}

The nice thing about this solution is that you can use it with all HttpMethod types.