1. 概述

本文将实现一个支持请求体的 HTTP DELETE 接口,并探索多种发送请求的方式。我们将对比主流 REST 客户端实现方案,踩坑指南直达核心问题。

2. 问题分析

HTTP 规范对 DELETE 请求是否支持请求体表述模糊:*"DELETE 请求中的内容没有普遍定义的语义"*。这导致具体实现由服务器决定。⚠️ 虽然技术上可行,但服务器不保证会处理 DELETE 请求体

我们将展示 Spring 的 @RestController 如何处理带请求体的 DELETE 请求。为简化验证,创建 /delete 接口直接返回请求体:

@RestController
@RequestMapping("/delete")
public class DeleteController {

    @DeleteMapping
    public Body delete(@RequestBody Body body) {
        return body;
    }
}

Body 是一个简单 POJO:

public class Body {
    private String name;
    private Integer value;

    // 标准 getter/setter
}

测试时使用固定 JSON 字符串,避免额外解析:

String json = "{\"name\":\"foo\",\"value\":1}"

现在探索支持请求体的 REST 客户端实现方案。

3. 使用 Spring RestTemplate

首选 Spring 的 RestTemplate。创建客户端类接收 URL:

public class SpringTemplateDeleteClient {

    private final String url;
    private RestTemplate client = new RestTemplate();

    public SpringTemplateDeleteClient(String url) {
        this.url = url;
    }

    // ...
}

RestTemplatedelete() 方法不支持请求体,需改用通用 exchange() 方法

public String delete(String json) {
    HttpHeaders headers = new HttpHeaders();
    headers.set("Content-Type", "application/json");

    HttpEntity<String> body = new HttpEntity<>(json, headers);

    ResponseEntity<String> response = client.exchange(
      url, HttpMethod.DELETE, body, String.class);
    return response.getBody();
}

验证接口正确处理请求体:

@Test
void whenRestTemplate_thenDeleteWithBody() {
    SpringTemplateDeleteClient client = new SpringTemplateDeleteClient(url);

    assertEquals(json, client.delete(json));
}

4. 使用 Java 原生 HttpClient

Java 11 的 HttpClient 没有直接支持请求体的 delete() 方法,需通过 method("DELETE") 实现

创建客户端类:

public class PlainDeleteClient {

    private final String url;
    private HttpClient client = HttpClient.newHttpClient();

    // URL 构造函数

    public String delete(String json) throws Exception {
        BodyPublisher body = HttpRequest.BodyPublishers.ofString(json);

        // ...
        
        HttpResponse<String> response = client.send(
          request, HttpResponse.BodyHandlers.ofString());
        return response.body();
    }
}

构建请求时使用 method("DELETE")

HttpRequest request = HttpRequest.newBuilder(URI.create(url))
  .header("Content-Type", "application/json")
  .method("DELETE", body)
.build();

测试验证:

@Test
void whenPlainHttpClient_thenDeleteWithBody() throws Exception {
    PlainDeleteClient client = new PlainDeleteClient(url);

    assertEquals(json, client.delete(json));
}

5. 使用 Apache HTTP 4

Apache HTTP 客户端是流行方案。标准实现如 HttpPost 继承 HttpEntityEnclosingRequestBase,提供 setEntity() 设置请求体。

**但 HttpDelete 只继承 HttpRequestBase,不支持请求体。需自定义 HttpDeleteBody 继承 HttpEntityEnclosingRequestBase**:

public class HttpDeleteBody extends HttpEntityEnclosingRequestBase {

    public HttpDeleteBody(final String uri) {
        super();
        setURI(URI.create(uri));
    }

    @Override
    public String getMethod() {
        return "DELETE";
    }
}

客户端实现:

public class ApacheDeleteClient {

    // URL 构造函数

    public String delete(String json) throws IOException {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            StringEntity body = new StringEntity(json, ContentType.APPLICATION_JSON);

            HttpDeleteBody delete = new HttpDeleteBody(url);
            delete.setEntity(body);

            CloseableHttpResponse response = client.execute(delete);
            return EntityUtils.toString(response.getEntity());
        }
    }
}

CloseableHttpClient 实现了 Closeable,使用 try-with-resources 确保资源释放。EntityUtils 辅助转换响应体。

5.1. 使用 Apache HTTP 5

**版本 5HttpDelete 已原生支持请求体,且请求执行改为异步模式,需构建 HttpClientResponseHandler**:

HttpDelete delete = new HttpDelete(url);
delete.setEntity(body);

HttpClientResponseHandler handler = response -> {
    try (HttpEntity entity = response.getEntity()) {
        return EntityUtils.toString(entity);
    }
};

return client.execute(delete, handler);

HttpEntity 现在也实现了 Closeable,必须使用 try-with-resources。

6. 总结

本文对比了多种支持请求体的 DELETE 请求客户端实现方案:

Spring RestTemplate:通过 exchange() 方法实现
Java 原生 HttpClient:使用 method("DELETE") 绕过限制
Apache HTTP 4:需自定义 HttpDeleteBody
Apache HTTP 5:原生支持,更简洁

选择取决于项目依赖和具体需求。完整代码见 GitHub


原始标题:HTTP DELETE With Request Body | Baeldung