找不到資料要回 404 還是 200?--延伸討論 204

TLDR

當找不到目標資源或是不想讓別人知道資源存在的時候,可以回 404。其他看情境回應,有可能是 200,也有可能是其他的狀態碼,例如:曾經存在,可以回 410。

204 沒規定不行,但以 GET 的語意來說是不適合的。

RESTful 亦同。

前情提要

可參考前一篇文章找不到資料要回 404 還是 200?

今天要討論的是另一個「好像」可以拿來選擇的狀態碼 204 No Content

204 的定義

首先不免俗的,先來看 RFC 9110 15.3.5. 204 No Content 定義是怎麼說的:

The 204 (No Content) status code indicates that the server has successfully fulfilled the request and that there is no additional content to send in the response content.

當 Server 成功地完成請求,且沒有額外的附加內容需要傳輸時,可以使用 204 狀態碼。

這裡應該蠻好理解的,接著看下一句:

Metadata in the response header fields refer to the target resource and its selected representation after the requested action was applied.

當請求動作處理完後,回應的 header 欄位要指出目標資源與它選定的 representation。對應的例子是 PUT 請求完後,回 204 狀態碼加 Etag 的 header。

再來看另外一句:

The 204 response allows a server to indicate that the action has been successfully applied to the target resource, while implying that the user agent does not need to traverse away from its current “document view” (if any).

則是在說 204 狀態碼代表的是 server 已完成請求動作,並暗示 User Agent 不需要離開當下的介面。對應的例子是編輯畫面的儲存按鈕,當成功的時候可以回應 204 狀態碼。

以 RFC 所提的這兩個例子來看,它的情境都是在說請求執行了某個操作(如 POST、PUT、DELETE 方法),而不是請求取得資源(如 GET 方法)。

與 200 的比較

雖然是這麼說,但 RFC 也沒說 GET 不能回應 204 狀態碼。

但不管怎麼說,我們還是先來看一下最熟悉的 200 狀態碼是怎麼說的:

(RFC 是用表格呈現 這裡描述的是我的理解)當 GET 方法時,representation 內容為目標資源。

在前一篇有提到,representation 代表的是資源的表示方法,像 application/json 是其中一種表示方法。如果沒有任何表示方法可以回應的話,這時應該要回 404 狀態碼。但如果有「沒有資料的表示方法」,即便是沒有資料,還是可以作為目標資源回應,這時就能夠回傳 200 狀態碼。

「沒有資料的表示方法」可以回傳 200 狀態碼,例如:

  1. 集合是空的,所以有「空集合」的表示方法。
  2. HTML 是空的,所以有「空 HTML」的表示方法。例如 Nginx GET 空的 .html 檔,也是回 200 狀態碼。
  3. 存取特定格式的資源,如果特定格式有定義沒有資料的表示方法。例如 Excel 檔案,當沒資料的時候會取得一個空範本。(只是這一類的例子實在很少見)

這取決如何定義 API「沒有資料的表示方法」,類似程式的空字串和 null 的差別:以強型別語言來看,空字串是能夠輸出的(對應 200 狀態碼情境),但 null 會出現例外錯誤(對應 404 狀態碼情境)。

再接著往下看,RFC 又提到了 204 狀態碼,而這裡應該就是關鍵了:

If some aspect of the request indicates a preference for no content upon success, the origin server ought to send a 204 (No Content) response instead.

某些時候,請求會期望當成功的時候不要有內容,可以使用 204 狀態碼。例如:PUT 更新完資料,只是想知道有沒有成功,而不在乎有沒有內容,這時成功即可回傳 204 狀態碼。

但,以 GET 方法的語意來看,怎麼會期望回傳不要有內容,因此 GET 方法不適合回傳 204 狀態碼。

參考資料