đang sử dụng PUT với tác dụng phụ có thể chấp nhận (REST)


9

Tôi muốn tạo lịch sử hoàn tác bất cứ khi nào người dùng cập nhật biểu mẫu. Vì đó là bản cập nhật, tôi muốn sử dụng yêu cầu PUT. Tuy nhiên, tôi đọc rằng PUT cần không có tác dụng phụ .

Có thể chấp nhận sử dụng PUT ở đây không? Có những lựa chọn thay thế tốt hơn?

PUT /person/F02E395A235

{
   time: 1234567,
   fields: {
      name: 'John',
      age: '41'
   }
}

Trong máy chủ

doPut('person/:personId',
   // create a new person snapshot
)

Biên tập:

Lịch sử sẽ hiển thị cho người dùng, gọi nhiều lần sẽ dẫn đến nhiều phiên bản.

Giải pháp là kiểm tra xem phiên bản có duy nhất không trước khi tạo.

Câu trả lời:


11

Những người soạn thảo HTTP / 2 dài dòng hơn rất nhiều về ý tưởng của họ về những gì HTTP nên làm, trong khi vẫn giữ nguyên ý nghĩa cũ. Chúng ta hãy xem thông số dự thảo HTTP / 2 nói gì về tính không ổn định:

4.2.2. Phương pháp tạm thời

Một phương thức yêu cầu được coi là "idempotent" nếu hiệu ứng dự định trên máy chủ của nhiều yêu cầu giống hệt với phương thức đó giống như hiệu ứng cho một yêu cầu như vậy. Các phương thức yêu cầu được xác định bởi đặc tả này, PUT, DELETE và yêu cầu an toàn phương pháp là idempotent.

Giống như định nghĩa về an toàn, thuộc tính idempotent chỉ áp dụng cho những gì đã được người dùng yêu cầu; một máy chủ có thể tự do ghi nhật ký từng yêu cầu, giữ lại lịch sử kiểm soát sửa đổi hoặc thực hiện các tác dụng phụ không bình thường khác cho mỗi yêu cầu tạm thời .

Các hiệu ứng thiết kế trên máy chủ cho mỗi yêu cầu một PUT như vậy là để cập nhật các tài nguyên xác định bởi rằng URI . Đây chính xác là những gì xảy ra trong trường hợp của bạn.

Rằng bạn quyết định phiên bản tài nguyên không thực sự quan trọng ở đây. Nếu bạn không muốn tạo phiên bản mới khi không có gì thay đổi, bạn sẽ cần so sánh tải trọng trong yêu cầu PUT với phiên bản tài nguyên gần đây nhất (hoặc được xác định khác) và khi không có thuộc tính nào thay đổi bạn có thể chọn không tạo phiên bản mới .


Chỉnh sửa của bạn:

Lịch sử sẽ hiển thị cho người dùng, gọi nhiều lần sẽ dẫn đến nhiều lần

Theo như tài nguyên có liên quan, đó không phải là tác dụng phụ . Tài nguyên tại URI đó không thay đổi (các thuộc tính tương tự nhận PUT). Lịch sử chỉ là siêu dữ liệu, vì rất có thể nó được yêu cầu bởi một URI khác hoặc với các tiêu đề yêu cầu khác nhau.


Ngoại trừ vì bạn trả lời vấn đề cụ thể của tôi: "PUT có thể chấp nhận để tạo lịch sử hiển thị cho người dùng không", và cho tôi một giải pháp, cảm ơn
roo2

Vấn đề là giải pháp đó là gì? Đó là timetài sản được cập nhật? Tôi nghĩ đó cũng là siêu dữ liệu, mặc dù nó nằm trong tài nguyên.
CodeCaster

1
Vấn đề là nếu nhiều PUT được gửi, người dùng sẽ nhận được một lịch sử hoàn tác dài với thông tin dư thừa. kiểm tra tính duy nhất sẽ giải quyết được điều đó
roo2

12

HTTP phân biệt giữa hai thuộc tính:

  • Vô tư
  • Sự an toàn

Idempotency được định nghĩa bởi thông số kỹ thuật như sau:

Các phương thức cũng có thể có thuộc tính " idempotence " trong đó (ngoài các vấn đề lỗi hoặc hết hạn), các tác dụng phụ của N> 0 yêu cầu giống hệt như đối với một yêu cầu. Các phương pháp GET, HEAD, PUTDELETEchia sẻ khách sạn này. Ngoài ra, các phương pháp OPTIONSTRACE KHÔNG NÊN có tác dụng phụ, và do đó vốn dĩ không có tác dụng.

Và an toàn:

Cụ thể, quy ước đã được thiết lập rằng GETHEADcác phương pháp KHÔNG NÊN có ý nghĩa của việc thực hiện một hành động nào khác ngoài truy xuất. Những phương pháp này nên được coi là " an toàn ". Điều này cho phép các tác nhân người dùng đại diện cho các phương thức khác, như POST, PUTDELETE, theo một cách đặc biệt, để người dùng nhận thức được thực tế rằng một hành động có thể không an toàn đang được yêu cầu.

Đương nhiên, không thể đảm bảo rằng máy chủ không tạo ra tác dụng phụ do thực hiện GETyêu cầu; trong thực tế, một số tài nguyên động coi đó là một tính năng. Sự khác biệt quan trọng ở đây là người dùng không yêu cầu các tác dụng phụ, do đó không thể chịu trách nhiệm cho họ.

Lưu ý rằng an toàn ngụ ý tính không ổn định: nếu một phương thức không có tác dụng phụ thì thực hiện nó nhiều lần sẽ mang lại hiệu quả phụ giống như thực hiện một lần, cụ thể là không có.

Điều này đặt các phương thức thành ba loại:

  • an toàn (và do đó cũng idempotent): GET, HEAD, OPTION,TRACE
  • idempotent nhưng không nhất thiết phải an toàn: PUT,DELETE
  • không bình thường cũng không an toàn: POST

PUT cần không có tác dụng phụ.

Điều đó là sai. PUTlà bình thường nhưng không an toàn. Các toàn bộ điểm của PUTlà phải có một tác dụng phụ, cụ thể là cập nhật một tài nguyên. Ý nghĩa của sự bình thường là việc cập nhật cùng một tài nguyên với cùng một nội dung nhiều lần sẽ có tác dụng tương tự như chỉ cập nhật một lần.

Lưu ý đoạn cuối trong phần về an toàn [nhấn mạnh của tôi]:

Đương nhiên, không thể đảm bảo rằng máy chủ không tạo ra tác dụng phụ do thực hiện GETyêu cầu; trong thực tế, một số tài nguyên động coi đó là một tính năng. Sự khác biệt quan trọng ở đây là người dùng không yêu cầu các tác dụng phụ, do đó không thể chịu trách nhiệm cho họ .

Mặc dù câu này nói về GETvà an toàn, chúng ta có thể giả định rằng các tác giả cũng có nghĩa là áp dụng lý do tương tự PUTvà tính không minh bạch. IOW: PUTchỉ nên có một hiệu ứng phụ hiển thị cho người dùng , cụ thể là cập nhật tài nguyên được đặt tên. Nó có thể có tác dụng phụ khác, nhưng người dùng không thể chịu trách nhiệm về chúng.

Ví dụ, thực tế PUTlà idempotent có nghĩa là tôi có thể thử lại thường xuyên như tôi muốn: thông số kỹ thuật đảm bảo rằng việc thực thi nó nhiều lần sẽ giống hệt như thực hiện nó một lần. Hoàn toàn hợp lệ để tạo ra một hồ sơ tồn đọng của các phiên bản cũ như là một tác dụng phụ của nhiều PUTyêu cầu đó. Tuy nhiên, nếu, do kết quả của nhiều lần thử lại, cơ sở dữ liệu của bạn sẽ lấp đầy một bản tồn đọng của các bản sửa đổi cũ, đó không phải là vấn đề của tôi, đó là của bạn.

IOW: bạn được phép có nhiều tác dụng phụ như bạn muốn, nhưng

  1. nó phải nhìn vào người dùng như thể các yêu cầu của họ là bình thường
  2. bạn chịu trách nhiệm cho những tác dụng phụ đó, không phải người dùng

Đúng, idempotency là về trạng thái của tài nguyên được đặt, chứ không phải về bất kỳ trạng thái máy chủ / dịch vụ nào khác bị ảnh hưởng bởi hành động của PUT.
Marjan Venema

Upvote cho lời giải thích tuyệt vời, về sự an toàn và
bình tĩnh

Giải thích tuyệt vời. Tuy nhiên, bạn đưa ra một số tuyên bố như thế này: "Toàn bộ quan điểm của PUT là có tác dụng phụ, cụ thể là cập nhật tài nguyên." Điều đó có vẻ như là một mâu thuẫn trừ khi bạn có nghĩa là một cái gì đó khác biệt bởi thuật ngữ "tác dụng phụ" hơn là "một cái gì đó thứ yếu hoặc vô ý xảy ra bên cạnh hiệu ứng chính, dự định."
MarredCheese

@MarredCheese: Tôi đang sử dụng thuật ngữ này theo nghĩa lập trình tiêu chuẩn của nó, về cơ bản có nghĩa là "bất kỳ" kết quả "nào không phải là giá trị trả về".
Jörg W Mittag

À, tất nhiên rồi. Cảm ơn bạn đã làm rõ.
MarredCheese

1

Bạn đúng là PUT cần không có tác dụng phụ , tuy nhiên tôi sẽ thêm vài thứ vào đây.

PUT cần không có tác động phụ đến tài nguyên mà hoạt động PUT đang được thực hiện

Bạn đang cập nhật một persontài nguyên được xác định là F02E395A235, vì vậy sử dụng PUT là chính xác. Bây giờ là một quy tắc kinh doanh, bạn cũng theo dõi các thay đổi vô hình đối với thực thể gọi (người tiêu dùng dịch vụ REST). Điều này sẽ không thêm một mục mới trong persontài nguyên. Ảnh chụp lịch sử sẽ không thể truy cập bằng cách sử dụng /person/điểm cuối. Vì vậy, tôi tin rằng, PUT nên được chấp nhận hoàn toàn trong trường hợp này.


1
Không có tác dụng phụ đối với tài nguyên được đặt, nhưng bất kỳ số lượng tác dụng phụ nào trên các công cụ khác (quầy, ghi nhật ký, dấu vết kiểm toán, ...) là hoàn toàn chấp nhận được.
Marjan Venema
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.