Tôi có nên trả lại phản hồi 204 hoặc 404 khi không tìm thấy tài nguyên không?


15

Tôi đang phát triển một dịch vụ RESTful đơn giản cho các giải đấu và lịch trình. Khi một giải đấu được tạo thông qua một yêu cầu POST chứa phần thân JSON, giải đấu được chèn vào một BiMap, được khai báo như sau trong triển khai DAO:

private BiMap<String, Tournament> tournaments = Maps.synchronizedBiMap(HashBiMap.create());

Khi một giải đấu được tạo, id chuỗi liên kết của nó được trả về để người dùng có thể có tham chiếu trong tương lai của giải đấu đó. Anh ấy / cô ấy có thể lấy lại thông tin từ giải đấu mới thực hiện yêu cầu sau:

GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39

Nhưng nếu không có giải đấu với id như vậy được tìm thấy thì sao? Cho đến nay, tôi đang trả lại một phản hồi 204. Vâng, Jersey đang làm điều đó cho tôi khi trở về nulltừ một trong những phương pháp của nó. Đây là phương pháp tương ứng với tuyến đường trên:

@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("id") String id) {
    Optional<Tournament> optTournament = tournamentDao.getTournament(id);
    if (optTournament.isPresent())
        return optTournament.get();
    return null;
}

Câu hỏi của tôi là: có thể trả lại 204: No Contentphản hồi hay 404thay vào đó là phản hồi vì tài nguyên không được tìm thấy?

Nếu tôi nên thay đổi nó thành 404, câu hỏi rõ ràng: Tôi nên thay đổi chữ ký phương thức phải không? Vì bây giờ một giải đấu (loại Tournament) có thể không được trả lại, nên phương thức sẽ khác. Tôi có nên sử dụng Responseloại như loại trả lại thay thế?

Câu trả lời:


32

HTTP 204có nghĩa là một cái gì đó đã được tìm thấy, nhưng nó trống rỗng. Ví dụ: hãy tưởng tượng rằng bạn đang phục vụ các tệp nhật ký thông qua HTTP, với các yêu cầu như http://example.com/logs/[date-goes-here] . Vào ngày 18 tháng 5 năm 2015:

  • http://example.com/logs/2015-05-19 sẽ trở lại HTTP 404, điều đó có nghĩa là không có nhật ký, bởi vì, thật khó để đăng nhập tương lai.

  • Tuy nhiên, http://example.com/logs/2015-05-18 sẽ trả về HTTP 200với các mục nhật ký trong nội dung của phản hồi hoặc HTTP 204nếu tệp nhật ký đã được tạo, nhưng vẫn chưa có nhật ký nào được ghi lại cho việc này ngày.

Nếu bạn cung cấp nullcho khung làm phản hồi cho một yêu cầu, thì nó giả định rằng bạn đã tìm thấy một mục nhập, và mục này là trống, do đó HTTP 204. Thay vào đó, bạn nên throw new NotFoundException();chỉ ra cho khung rằng mục nhập không tồn tại, để nó sẽ tạo ra một HTTP 404.

Nếu tôi nên thay đổi nó thành 404, câu hỏi rõ ràng: Tôi nên thay đổi chữ ký phương thức phải không?

Không, bạn không. Đó là điều tốt đẹp về throw new NotFoundException();. Nó sẽ hoạt động bất kể loại trả về thực tế của phương thức của bạn là gì.


5
Lưu ý đặc biệt về RFC 2616 . 204 phản hồi chỉ tuân thủ thông số kỹ thuật nếu bạn hoàn toàn bỏ qua phần thân thư. Ở một mức độ nào đó, quan điểm của một phản hồi 204 là nói, "không, đó không phải là một tai nạn mà tôi không trả lại nội dung." Để mở rộng trên ví dụ của MainMa: Nếu một công cụ tra cứu nhật ký nhổ ra các tệp văn bản (ví dụ: một trình bao bọc mỏng xung quanh các tệp nhật ký chỉ tạo ra tệp nhật ký như hiện tại), 204 sẽ phù hợp với tệp nhật ký trống. Nếu phản hồi là một đối tượng JSON trống (ví dụ {content: ''}:), thì phản hồi 204 sẽ không phù hợp.
Brian

" Bởi vì, tốt, thật khó để ghi lại tương lai. " - Bit này phụ thuộc vào một ngày tùy ý; tại sao không biến nó thành thứ gì đó không đòi hỏi người đọc phải giả vờ không phải hôm nay? Có lẽ sử dụng 2015-02-29sẽ tốt hơn, vì đó là một ngày hoàn toàn không tồn tại?
Vụ kiện của Quỹ Monica


1

Yêu cầu của bạn là GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39.

Nếu http://localhost:8080/eventscheduler/không tồn tại dưới dạng điểm cuối, bạn nên trả về 404. Bạn đang cố truy cập tài nguyên ( /eventscheduler/) không tồn tại. Điều này sẽ cho khách hàng biết rằng máy chủ tồn tại localhost:8080, nhưng không có gì ở eventschedulerđiểm cuối.

Nếu http://localhost:8080/eventscheduler/tồn tại dưới dạng điểm cuối nhưng tài nguyên bắt buộc không có sẵn, lỗi 5xx là phù hợp. Một ví dụ điển hình cho điều này sẽ là nếu cơ sở dữ liệu ngoại tuyến, nơi bạn có thể trả về 503. Tất nhiên, bạn có thể chỉ muốn trả về một lỗi 500 chung chung thay vì một trường hợp cụ thể.

Nếu http://localhost:8080/eventscheduler/tồn tại nhưng thứ được thể hiện bởi c15268ce-474a-49bd-a623-b0b865386f39không tồn tại, tôi sẽ trả lại 200 với phần thân chỉ ra các chi tiết. Điểm cuối tồn tại, yêu cầu được đưa ra là hoàn toàn hợp lệ và có thể được xử lý, nhưng không có kết quả khớp.

Nếu yêu cầu của khách hàng của bạn đến điểm cuối không hợp lệ, bạn sẽ xem xét các lỗi 4xx khác. Bạn có thể chỉ ra rằng ứng dụng khách không được phép truy cập điểm cuối hoặc (các) mục được yêu cầu với 401 hoặc 403 hoặc có thể sử dụng 400 để cho biết rằng yêu cầu không hợp lệ. Với bất kỳ trong số này, thông tin bổ sung có thể được cung cấp trong cơ quan phản hồi.


Không cần phân biệt điểm cuối và tài nguyên. Nếu URI không khớp với bất kỳ tài nguyên nào, vì bất kỳ lý do gì, máy chủ sẽ trả về 404.
bdsl

Kiểm tra mã phản hồi trên trang web này để biết ví dụ về một trang web đang làm đúng. Đó là một trang web, không phải API, nhưng áp dụng cùng một thông số http. softwareengineering.stackexchange.com/questions/266183385
bdsl 24/03/18

@bdsl Tôi có thể nói với bạn điều đó là hoàn toàn sai. Ví dụ: tôi đang tương tác với một dịch vụ người dùng có thể trả về hồ sơ người dùng. Hãy nói rằng điểm cuối này được /uservà được sử dụng như thế nào /user?email=test@example.com. Là người tiêu dùng API, tôi muốn biết /uservì lý do nào đó không tồn tại trên máy chủ (có thể nó đã được thêm vào v2 của API và máy chủ ở trên v1 hoặc được đổi tên thành v3) hoặc nếu người dùng có email test@example.comkhông tồn tại. Đầu tiên là 404, thứ hai là 200 với phần thân cho biết không có người dùng nào có địa chỉ email đó.
Thomas Owens

@bdsl Điều đó thật tuyệt, nhưng điều đó không có nghĩa là nó đúng hay tốt nhất. Tôi cũng không nghĩ rằng bạn có thể so sánh một trang web được thiết kế cho sự tương tác của con người thông qua trình duyệt web so với API được thiết kế để sử dụng trong hệ thống phần mềm.
Thomas Owens

1
Vấn đề này được thảo luận thêm trong youtube.com/watch?v=nSKp2StlS6s
bdsl
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.