Tại sao phương pháp PATCH không phải là idempotent?


48

Tôi đã tự hỏi về điều này.

Giả sử tôi có một usertài nguyên với idnamecác lĩnh vực. Nếu tôi muốn cập nhật một trường, tôi chỉ có thể thực hiện một yêu cầu VÒI với tài nguyên như thế này

PATCH /users/42
{"name": "john doe"} 

Và sau đó ứng dụng sẽ cập nhật tên người dùng 42.

Nhưng tại sao nếu tôi lặp lại yêu cầu này thì kết quả sẽ khác?

Theo RFC 5789

PATCH không an toàn cũng không bình thường


Điều gì xảy ra nếu giữa các yêu cầu người khác thực hiện yêu cầu cập nhật người dùng 42{"name": "bendjamin franklin"}
gnat

@gnat không phải là một đối số tương tự giữ cho phương thức PUT mà thay vào đó được coi là idempotent? (xem goo.gl/t24ZSJ )
mattecapu

"PUT có ngữ nghĩa tạm thời và do đó có thể được sử dụng một cách an toàn cho các cập nhật tuyệt đối (nghĩa là chúng tôi gửi toàn bộ trạng thái của tài nguyên đến máy chủ), nhưng cũng không phải cho các cập nhật tương đối (nghĩa là chúng tôi chỉ gửi các thay đổi về trạng thái tài nguyên) , vì điều đó sẽ vi phạm ngữ nghĩa của nó ... "( yêu cầu POST và PUT - có phải chỉ là quy ước không? )
gnat

1
Rõ ràng ... Nhưng bạn có thể nói PUT không bình thường vì giữa hai yêu cầu bằng nhau, khách hàng thứ hai có thể đưa ra yêu cầu thứ ba ở giữa hai Nhưng vì chúng tôi không quan tâm đến dữ liệu trước đó, nên đó không phải là vấn đề. Đối số tương tự giữ cho các yêu cầu PATCH.
mattecapu

2
Tôi có quyền tự do thêm một tham chiếu đến đặc tả kỹ thuật có liên quan, vì tôi tin rằng nó có liên quan cao trong bối cảnh của câu hỏi này.
Pete

Câu trả lời:


34

Một yêu cầu PATCH có thể là idempotent, nhưng nó không bắt buộc phải có. Đó là lý do nó được đặc trưng là không bình thường.

Việc PATCH có thể bình thường hay không phụ thuộc mạnh mẽ vào cách các thay đổi cần thiết được truyền đạt.
Ví dụ: nếu định dạng bản vá ở dạng {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, thì bất kỳ yêu cầu PATCH nào sau yêu cầu đầu tiên sẽ có hiệu ứng khác (phản hồi thất bại) so với yêu cầu đầu tiên.
Một lý do khác cho sự không bình thường có thể là việc áp dụng sửa đổi trên một thứ khác ngoài tài nguyên ban đầu có thể khiến tài nguyên không hợp lệ. Điều này sau đó cũng sẽ là trường hợp nếu bạn áp dụng thay đổi nhiều lần.


3
Tôi không hiểu đoạn cuối, bạn có thể đưa ra một ví dụ về cách "áp dụng sửa đổi trên một thứ khác ngoài tài nguyên ban đầu có thể khiến tài nguyên không hợp lệ" và điều này liên quan đến việc áp dụng thay đổi nhiều lần cho cùng một tài nguyên không?
Robin Green

3
@RobinGreen: Giả sử rằng tài nguyên được biểu diễn bằng XML với yêu cầu có nhiều nhất một <name>phần tử. Nếu PATCH thêm một <name>phần tử vào tài nguyên mà ban đầu không chứa một tài nguyên, thì việc áp dụng PATCH hai lần (hoặc áp dụng nó cho tài nguyên đã chứa a <name>) làm cho tài nguyên không hợp lệ, vì nó đột nhiên chứa hai <name>phần tử không được phép cho các tài nguyên như vậy.
Bart van Ingen Schenau

13
Ví dụ đầu tiên bạn đưa ra không phải là IMHO có liên quan vì nó là idempotent. Ví dụ với DELETE là idempotent, yêu cầu đầu tiên: tài nguyên tồn tại nhưng đã bị xóa (trả về 2xx), yêu cầu thứ hai: tài nguyên không tồn tại và vẫn không tồn tại sau yêu cầu, trả về 4xx. Trạng thái máy chủ đã không thay đổi, do đó, tính không thay đổi. Trong ví dụ của bạn, yêu cầu đầu tiên: PATCH từ BenFra đến JohDoe, tên tài nguyên là BenFra nhưng bây giờ là JohDoe (trả về 2xx), yêu cầu thứ hai: PATCH từ BenFra đến JohDoe, tên tài nguyên là JohDoe và vẫn là JohDoe (trả về 4xx). Vì vậy, điều này không cho thấy PATCH có thể là không phổ biến.
sp00m

Thêm chi tiết tại đây: stackoverflow.com/q
4088350/1225328

8

Tôi nghĩ rằng câu trả lời rõ ràng khi PATCH không bình thường là đoạn này từ RFC 5789:

Cũng có trường hợp các định dạng vá không cần hoạt động từ một điểm gốc đã biết (ví dụ: nối các dòng văn bản vào tệp nhật ký hoặc các hàng không va chạm vào các bảng cơ sở dữ liệu), trong trường hợp đó không cần sự chăm sóc tương tự trong các yêu cầu của máy khách .

Vì RFC chỉ định rằng bản vá chứa một số "thay đổi chung" đối với tài nguyên, chúng ta nên nhìn xa hơn chỉ là trường thay thế điển hình. Nếu tài nguyên dành cho bộ đếm, thì bản vá có thể yêu cầu gia tăng, rõ ràng không phải là idempotet.


2

PATCHcác yêu cầu mô tả một tập hợp các hoạt động được áp dụng cho một tài nguyên, nếu bạn áp dụng cùng một tập hợp các hoạt động hai lần cho cùng một tài nguyên, kết quả có thể không giống nhau. Điều này là do việc xác định các hoạt động là tùy thuộc vào bạn. Nói cách khác, bạn phải xác định các quy tắc hợp nhất .

Hãy nhớ rằng một PATCHyêu cầu có thể được sử dụng để vá tài nguyên ở nhiều định dạng khác nhau, không chỉ JSON.

Vì vậy, một PATCHyêu cầu có thể là idempotent nếu bạn xác định các quy tắc hợp nhất là idempotent .

Ví dụ tạm thời:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

Ví dụ không bình thường:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

Trong ví dụ thứ hai, tôi đã sử dụng cú pháp "Mongo like" mà tôi đã tạo ra để tăng một thuộc tính. Rõ ràng đây không phải là idempotent, vì gửi cùng một yêu cầu nhiều lần sẽ dẫn đến kết quả khác nhau mỗi lần.

Bây giờ bạn có thể tự hỏi nếu sử dụng một cú pháp tạo nên như vậy là hợp lệ. Theo tiêu chuẩn , đó là:

Sự khác biệt giữa các yêu cầu PUT và PATCH được phản ánh trong cách máy chủ xử lý thực thể kèm theo để sửa đổi tài nguyên được xác định bởi URI yêu cầu. Trong yêu cầu PUT, thực thể kèm theo được coi là phiên bản sửa đổi của tài nguyên được lưu trữ trên máy chủ gốc và máy khách đang yêu cầu thay thế phiên bản đã lưu trữ. Tuy nhiên, với PATCH, thực thể kèm theo chứa một tập hợp các hướng dẫn mô tả cách tài nguyên hiện đang cư trú trên máy chủ gốc nên được sửa đổi để tạo ra một phiên bản mới.

Và bạn cũng có thể tự hỏi liệu có an tâm khi sử dụng PATCHcác yêu cầu theo cách này hay không, và nhiều người cho rằng chúng không phải, đây là một câu trả lời tốt với nhiều ý kiến ​​về vấn đề này.

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.