知識庫 / REST RSS 訂閱

HTTP DELETE 請求體

REST,Spring Web
HongKong
10
03:35 AM · Dec 06 ,2025

1. 簡介

本快速教程將實現一個 HTTP DELETE 終點,該終點接受請求體,然後探索多種方法將其發送到該終點。 此外,我們還將使用不同的流行 REST 客户端實現進行探索。

2. 問題

RFC規範對DELETE請求是否可以包含請求體存在歧義,明確指出“DELETE請求收到的內容沒有明確的語義。” 這使得實現者可以自行定義行為。儘管在DELETE請求中包含請求體在技術上是可能的,但服務器並不能保證接受或處理它。

我們將研究Spring的RestController 如何接受和處理DELETE請求中的@RequestBody。 為了簡化起見,我們將創建一個/delete 端點,它會回顯請求體,從而驗證請求體是否被正確處理:

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

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

我們的身體是一個簡單的POJO:

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

    // standard getters and setters
}

在我們的測試中,我們將使用簡單的 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()方法,並使用HttpMethod.DELETE 讓我們看看它的樣子:

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();
}

由於我們的控制器精確地返回接收到的內容,因此我們可以斷定它正確地處理了 DELETE 請求中的內容:

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

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

4. 使用核心 Java 類

Java 11 中的 HttpClient 缺少支持 Body 的專用 delete() 方法,因此我們使用泛型方法 “DELETE” 在 HttpRequest.newBuilder() 中。

讓我們使用相同的總體模板創建一個客户端,該客户端構造一個包含 delete() 方法的 URL。 我們將接收一個 JSON String 並使用該方法構造一個 BodyPublisher 。 最終,我們將返回響應體作為 String

public class PlainDeleteClient {

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

    // url constructor

    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();
    }
}

為了實際請求,我們將使用 HttpRequest.newBuilder(),它不包含一個接受 bodydelete() 輔助方法。相反,我們將使用通用的 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 客户端

使用 Apache HTTP 客户端是一個流行的選擇。藉助這個庫,標準實現如 <em>HttpPost</em> 擴展了 <em>HttpEntityEnclosingRequestBase</em>,其中包含一個 <em>setEntity()</em> 方法,允許我們在請求中包含一個主體。

<strong>不幸的是,HttpDelete只擴展了HttpRequestBase,它不包含定義請求實體的途徑。因此,我們首先通過擴展HttpEntityEnclosingRequestBase創建一個自定義HttpDeleteBody,它返回DELETE作為 HTTP 方法。</strong> 我們還將包含一個接受String` URL 的構造函數:``

public class HttpDeleteBody extends HttpEntityEnclosingRequestBase {

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

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

然後,我們可以將其實例化在我們的客户端,並調用 setEntity() 方法傳遞我們的內容。最後,我們使用它與 client.execute() 方法一起使用:

public class ApacheDeleteClient {

    // url constructor

    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 HTTP 請求的客户端實現方案。每種方案各有優勢,選擇取決於我們的具體需求,例如依賴偏好。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.