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;
}
// ...
}
RestTemplate
的 delete()
方法不支持请求体,需改用通用 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
**版本 5 的 HttpDelete
已原生支持请求体,且请求执行改为异步模式,需构建 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。