Tạo yêu cầu với POST, mã phản hồi 200 hoặc 201 và nội dung


125

Giả sử tôi viết một dịch vụ REST có mục đích là thêm một mục dữ liệu mới vào hệ thống.

Tôi dự định ĐĂNG lên

http://myhost/serviceX/someResources

Giả sử điều đó hoạt động, tôi nên sử dụng mã phản hồi nào? Và tôi có thể trả lại nội dung nào.

Tôi đang xem các định nghĩa về mã phản hồi HTTP và thấy các khả năng sau:

200: Trở lại một thực thể mô tả hoặc chứa kết quả của hành động;

201: có nghĩa là ĐÃ ĐƯỢC TẠO. Ý nghĩa * Yêu cầu đã được thực hiện và dẫn đến một tài nguyên mới được tạo ra. Tài nguyên mới được tạo có thể được tham chiếu bởi (các) URI được trả về trong thực thể của phản hồi, với URI cụ thể nhất cho tài nguyên được cung cấp bởi trường tiêu đề Vị trí. Phản hồi NÊN bao gồm một thực thể chứa danh sách các đặc điểm tài nguyên và (các) vị trí mà từ đó người dùng hoặc tác nhân người dùng có thể chọn một thực thể thích hợp nhất. Định dạng thực thể được chỉ định bởi loại phương tiện được cung cấp trong trường tiêu đề Loại-Nội dung. *

Cái sau có vẻ phù hợp hơn với thông số Http, nhưng tôi không rõ

Phản hồi NÊN bao gồm một thực thể chứa danh sách các đặc điểm tài nguyên và (các) vị trí

có nghĩa.

Khuyến nghị? Diễn giải?

Câu trả lời:


77

Ý tưởng là cơ quan phản hồi cung cấp cho bạn một trang liên kết bạn với điều:

201 Tạo

Mã trạng thái 201 (Đã tạo) chỉ ra rằng yêu cầu đã được thực hiện và dẫn đến một hoặc nhiều tài nguyên mới được tạo. Tài nguyên chính được tạo bởi yêu cầu được xác định bởi trường tiêu đề Vị trí trong phản hồi hoặc nếu không nhận được trường Vị trí bằng URI yêu cầu hiệu quả.

Đây có nghĩa là bạn sẽ bao gồm một Locationtrong những phản ứng tiêu đề cung cấp cho URL của nơi bạn có thể tìm ra mới được tạo điều :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Cơ quan phản hồi

Sau đó, họ tiếp tục đề cập đến những gì bạn nên đưa vào phản ứng cơ thể :

Tải trọng phản hồi 201 thường mô tả và liên kết đến (các) tài nguyên được tạo.

Đối với người sử dụng trình duyệt, bạn cung cấp cho họ thứ gì đó để họ có thể xem và nhấp vào, để truy cập tài nguyên mới được tạo của họ:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Nếu trang chỉ được sử dụng bởi rô-bốt, thì điều hợp lý là máy tính có thể đọc được phản hồi:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Hoặc, nếu bạn thích:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

Câu trả lời là hoàn toàn tùy thuộc vào bạn; đó là tùy ý những gì bạn muốn.

Thân thiện với bộ nhớ cache

Cuối cùng, có sự tối ưu hóa mà tôi có thể lưu vào bộ nhớ cache trước tài nguyên đã tạo (vì tôi đã có nội dung; tôi vừa tải nó lên). Máy chủ có thể trả về ngày tháng hoặc ETag mà tôi có thể lưu trữ cùng với nội dung tôi vừa tải lên:

Xem Phần 7.2 để thảo luận về ý nghĩa và mục đích của các trường tiêu đề trình xác thực, chẳng hạn như ETag và Last-Modified, trong phản hồi 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

ETags hoàn toàn là các giá trị tùy ý. Làm cho chúng khác nhau khi tài nguyên thay đổi (và bộ nhớ đệm cần được cập nhật) là tất cả những gì quan trọng. ETag thường là một hàm băm (ví dụ: SHA2). Nhưng nó có thể là một cơ sở dữ liệu rowversionhoặc một số sửa đổi tăng dần. Bất cứ điều gì sẽ thay đổi khi sự vật thay đổi.


Cho đến nay câu trả lời của bạn có vẻ hợp lý nhất. Tôi hơi lo lắng về bản thể luận của phản ứng, nhưng ngoài điều đó, nó có vẻ như là cách giải thích thuần thục nhất về thông số kỹ thuật. Tôi tò mò nếu có bất kỳ cách "đáp ứng" nhẹ nào để xử lý đầu ra của con người / máy móc. nhưng chủ yếu là tôi bị hấp dẫn bởi đề xuất "lưu vào bộ nhớ đệm đầu vào của riêng bạn". Hầu hết các ứng dụng web mà tôi biết sẽ không tạo phiên bản 1: 1 của tài nguyên. Ngay cả khi nó là một cái gì đó tầm thường như bình thường hóa viết hoa của một chuỗi. Không phải là một chút khôn ngoan khi coi phiên bản đã gửi của bạn là phiên bản mà etag được tạo ra?
Anthony

1
@Anthony, bộ nhớ đệm: nó có thể là một loại ứng dụng lưu trữ tệp 1: 1. So sánh ví dụ: WebDAV PUT & POST. Các tập tin lớn cần được xử lý.
kxr

@Anthony Tùy thuộc vào bạn nếu bạn muốn trả lại ETag cho khách hàng. Nếu nội dung khách hàng vừa tải lên không phải là nội dung bạn đã lưu, thì đừng trả lại ETag. Đó là sự linh hoạt của bạn và sự lựa chọn của bạn.
Ian Boyd

Tại sao câu trả lời của bạn thiếu Nội dung-Độ dài?
Vinnie Falco

1
@VinnieFalco Đây là câu trả lời về mã phản hồi 201. Nội dung-Độ dài đã được giải thích cho các mục đích trưng bày.
Ian Boyd

91

Tôi nghĩ rằng atompub REST API là một ví dụ tuyệt vời về một dịch vụ tốt. Xem đoạn mã dưới đây từ thông số atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

Máy chủ báo hiệu việc tạo thành công với mã trạng thái là 201. Phản hồi bao gồm tiêu đề Vị trí cho biết URI Mục nhập Thành viên của Mục nhập Atom và đại diện của Mục nhập đó trong nội dung phản hồi.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

Mục nhập do Bộ sưu tập tạo và trả lại có thể không khớp với Mục nhập được khách hàng ĐĂNG. Máy chủ CÓ THỂ thay đổi giá trị của các phần tử khác nhau trong Mục nhập, chẳng hạn như giá trị nguyên tử: id, nguyên tử: cập nhật và nguyên tử: tác giả và CÓ THỂ chọn xóa hoặc thêm các phần tử và thuộc tính khác hoặc thay đổi nội dung phần tử và giá trị thuộc tính.


9
Trả lại tài nguyên tạo ra có thể là một chút nhiều, nếu tài nguyên là trong gigabyte độ lớn ...
Tor Valamo

10
Đã đồng ý! Đó là sự tối ưu hóa của sự cần thiết-- nhưng bạn không muốn làm điều đó quá sớm. Điều quan trọng là thiết kế với tinh thần yên tĩnh và chỉ thực hiện các ngoại lệ khi chúng cần thiết.
Chandra Patni

3
@ChandraPatni, Atom đã chết . Cần những ví dụ tốt hơn.
Pacerier

16
Atom có ​​thể đã chết, nhưng tinh thần của ví dụ vẫn còn nguyên.
Ashimema

2
Giải thích ban đầu của tôi về phản hồi 201 giống như "này, bạn muốn tạo một tài nguyên, nhưng dựa trên ngữ cảnh, bạn không quan tâm đến kết quả cuối cùng hoặc có quyền ghi nhưng không có quyền đọc tài nguyên này. Trong trường hợp, tất cả những gì bạn cần trước khi quay lại bộ sưu tập chính là URL của tài nguyên đã tạo. Để làm bằng chứng, nó đã được tạo. " Về cơ bản, bất cứ điều gì vượt quá mức đó đều giống như một phản hồi 200. Trừ khi RFC có ý nghĩ khác.
Anthony

50

Trong một vài từ:

  • 200 khi một đối tượng được tạo trả về
  • 201 khi một đối tượng được tạo nhưng chỉ trả về tham chiếu của nó (chẳng hạn như ID hoặc liên kết)

Nguồn cho cái này?
sudo soul


3
Sau khi đọc tools.ietf.org/html/rfc7231#section-6.3.1 , tôi đồng ý với cách hiểu này - tôi cho rằng tôi đang hỏi thêm về cách bạn đến được với nó. Nhưng bây giờ theo hiểu biết của tôi ... 200 = tài nguyên được tạo và trả về | 201 = tài nguyên được tạo và tham chiếu được trả về | 204 = tài nguyên được tạo và không có tải trọng nào được trả lại
sudo soul

34

Kiểm tra HTTP: Định nghĩa phương pháp: POST .

Hành động được thực hiện bởi phương thức POST có thể không dẫn đến tài nguyên có thể được xác định bằng URI. Trong trường hợp này, 200 (OK) hoặc 204 (Không có nội dung) là trạng thái phản hồi thích hợp, tùy thuộc vào việc phản hồi có bao gồm thực thể mô tả kết quả hay không.

Nếu tài nguyên đã được tạo trên máy chủ gốc, phản hồi NÊN là 201 (Đã tạo) và chứa một thực thể mô tả trạng thái của yêu cầu và đề cập đến tài nguyên mới và tiêu đề Vị trí (xem phần 14.30).


18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

Nó chỉ là một khóa-giá trị được phân tách bằng dấu hai chấm.

ETag: "xyzzy"

Nó có thể là bất kỳ loại dữ liệu văn bản nào - tôi thường bao gồm một chuỗi JSON với số nhận dạng của mục được tạo. Chỉ riêng việc dễ dàng thử nghiệm cũng khiến việc bao gồm nó trở nên đáng giá.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

Trong ví dụ này, số nhận dạng, tiểu và loại của mục được tạo là "đặc điểm và vị trí tài nguyên".


3
Bạn đang nói rằng một ETag tương ứng với một thực thể chứa danh sách các đặc điểm tài nguyên và (các) vị trí . Tôi có thể thấy rằng đề xuất của bạn là tốt, rất đồng ý với quan điểm của bạn về thử nghiệm. Tuy nhiên, tôi không thấy điều này phù hợp với "danh sách các đặc điểm và vị trí tài nguyên" như thế nào.
djna

"Danh sách các đặc điểm và vị trí tài nguyên" sẽ là nội dung của bất kỳ cấu trúc dữ liệu nào được cung cấp. Việc triển khai nghiêm ngặt hơn sẽ là cấu trúc JSON bao gồm uri tài nguyên và có thể là loại tài nguyên đã được tạo. Tôi sẽ điều chỉnh câu trả lời như vậy.
tempire

7
Nêu rõ các vấn đề để mọi người có thể tìm hiểu. Nếu không, bình luận chỉ là xua tay.
tempire

@SimonGibbs Vấn đề gì?
MEMark

2
Mặc dù nó hoàn toàn chính xác theo thông số kỹ thuật, nó đề xuất một tùy chọn triển khai rất bất thường. Ngoài ra, nó không thực sự trả lời câu hỏi ở đầu trang (hoặc nếu không nó sẽ làm như vậy bằng cách trộn các từ ETag và entity). Câu trả lời với 43 phiếu bầu có lẽ tốt hơn.
Simon Gibbs

1

Đầu ra thực sự phụ thuộc vào loại nội dung được yêu cầu. Tuy nhiên, tối thiểu bạn nên đặt tài nguyên đã được tạo ở Vị trí. Cũng giống như mô hình Post-Redirect-Get.

Trong trường hợp của tôi, tôi để trống cho đến khi có yêu cầu khác. Vì đó là hành vi của JAX-RS khi sử dụng Response.create ().

Tuy nhiên, chỉ cần lưu ý rằng các trình duyệt và khuôn khổ như Angular không tự động tuân theo 201. Tôi đã ghi nhận hành vi trong http://www.trajano.net/2013/05/201-create-with-angular-resource/


-2

Một câu trả lời khác mà tôi sẽ có cho điều này là thực hiện một cách tiếp cận thực dụng và giữ hợp đồng REST API của bạn đơn giản. Trong trường hợp của tôi, tôi đã cấu trúc lại API REST của mình để làm cho mọi thứ dễ kiểm tra hơn mà không cần dùng đến JavaScript hoặc XHR, chỉ cần các liên kết và biểu mẫu HTML đơn giản.

Vì vậy, để cụ thể hơn về câu hỏi của bạn ở trên, tôi chỉ sử dụng mã trả về 200và thông báo trả về chứa thông báo JSON mà ứng dụng của bạn có thể hiểu được. Tùy thuộc vào nhu cầu của bạn, nó có thể yêu cầu ID của đối tượng mới được tạo để ứng dụng web có thể lấy dữ liệu trong một cuộc gọi khác.

Một lưu ý, trong hợp đồng API được tái cấu trúc của tôi, phản hồi POST không được chứa bất kỳ dữ liệu có thể lưu vào bộ nhớ cache nào vì POST không thực sự có thể truy cập được, vì vậy hãy giới hạn nó ở những ID có thể được yêu cầu và lưu vào bộ nhớ cache bằng cách sử dụng yêu cầu GET.

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.