POST HTTP với các tham số truy vấn URL - ý tưởng tốt hay không? [đóng cửa]


451

Tôi đang thiết kế một API để vượt qua HTTP và tôi tự hỏi nếu sử dụng lệnh HTTP POST, nhưng chỉ với các tham số truy vấn URL và không có phần thân yêu cầu, là một cách tốt để đi.

Cân nhắc:

  • "Thiết kế web tốt" yêu cầu các hành động không bình thường được gửi qua POST. Đây là một hành động không bình thường.
  • Việc phát triển và gỡ lỗi ứng dụng này sẽ dễ dàng hơn khi các tham số yêu cầu có trong URL.
  • API không dành cho sử dụng rộng rãi.
  • Có vẻ như việc thực hiện một yêu cầu POST không có phần thân sẽ tốn nhiều công sức hơn, ví dụ như một Content-Length: 0tiêu đề phải được thêm rõ ràng.
  • Đối với tôi, dường như một POST không có phần thân là một chút trái ngược với hầu hết các kỳ vọng của các nhà phát triển và HTTP.

Có bất kỳ cạm bẫy hoặc lợi thế nào để gửi tham số trên một yêu cầu POST thông qua truy vấn URL thay vì cơ thể yêu cầu không?

Chỉnh sửa: Lý do điều này đang được xem xét là các hoạt động không bình thường và có tác dụng phụ khác ngoài truy xuất. Xem thông số kỹ thuật HTTP :

Cụ thể, quy ước đã được thiết lập rằng các phương thức GET và HEAD 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, chẳng hạn như POST, PUT và DELETE, 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.

...

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 thức GET, Head, PUT và DELETE chia sẻ thuộc tính này. Ngoài ra, các phương thức TÙY CHỌN và TRACE KHÔNG NÊN có tác dụng phụ, và do đó vốn dĩ không có tác dụng.


11
Tại sao lại sử dụng POST nếu bạn không cung cấp dữ liệu trong cơ thể?
Sunny Milenov

114
Bởi vì hoạt động không phải là idempotent.
Steven Huwig

20
@Jared, lưu ý rằng từ "REST" không xuất hiện trong câu hỏi này từ 2,5 năm trước. :) Thông số HTTP về tính không thay đổi được áp dụng bất kể kiến ​​trúc của tháng là gì đối với các dịch vụ web. May mắn thay, hệ thống mà API này được thiết kế để ủy quyền đã bị lỗi thời.
Steven Huwig

5
Bởi vì nhật ký máy chủ không ghi lại các tham số POST, nhưng chúng ghi lại các chuỗi truy vấn. Việc chạy một loạt các yêu cầu mà không cần đưa nó vào trình duyệt sẽ dễ dàng hơn nhiều, và sau đó nhìn vào truy nguyên, hơn là nhấp qua chúng. Ngoài ra, API không phải là trình duyệt đến máy chủ, mà là máy chủ đến máy chủ. Quan trọng nhất, toàn bộ sự việc đã được đóng hộp. :)
Steven Huwig

13
Đối với bất kỳ ai khác không biết ý nghĩa của idempotent: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg

Câu trả lời:


259

Nếu hành động của bạn không bình thường, thì bạn PHẢI sử dụng POST. Nếu bạn không, bạn chỉ yêu cầu sự cố xuống dòng. GET, PUTDELETEphương pháp này đòi hỏi phải idempotent. Hãy tưởng tượng những gì sẽ xảy ra trong ứng dụng của bạn nếu ứng dụng khách đang tìm nạp trước mọi GETyêu cầu có thể cho dịch vụ của bạn - nếu điều này sẽ gây ra tác dụng phụ cho khách hàng, thì có gì đó không đúng.

Tôi đồng ý rằng việc gửi một POSTchuỗi truy vấn nhưng không có phần thân có vẻ kỳ quặc, nhưng tôi nghĩ nó có thể phù hợp trong một số tình huống.

Hãy nghĩ về phần truy vấn của URL như một lệnh đối với tài nguyên để giới hạn phạm vi của yêu cầu hiện tại. Thông thường, các chuỗi truy vấn được sử dụng để sắp xếp hoặc lọc một GETyêu cầu (như ?page=1&sort=title) nhưng tôi cho rằng nó có ý nghĩa đối POSTvới việc cũng giới hạn phạm vi (có thể như thế ?action=delete&id=5).


4
Tôi đã chọn câu trả lời này cho trường hợp cụ thể này, nhưng tôi nghĩ rằng lập luận của R. Bemrose hấp dẫn đối với các API công khai.
Steven Huwig 15/03/2016

4
Tôi không nghĩ câu trả lời của anh ấy là đúng. Nếu bạn biết các tham số URL cho bài đăng biểu mẫu của mình khi trang HTML được gửi đến máy khách, bạn có thể giải quyết các tham số URL đó cho thuộc tính hành động của biểu mẫu, nếu không JavaScript có thể đặt tham số URL khi biểu mẫu được gửi.
Don McCaughey

3
Làm thế nào về một bài đăng của một tệp xml đến một url với các tham số truy vấn? điều đó có thể không?
OpenCoderX

3
Một ví dụ khác: dữ liệu yêu cầu có thể ở thực thể http, trong khi định dạng phản hồi được yêu cầu được truyền trong tham số truy vấn ( /action?response_format=json)
rds

4
+1 đã học được điều gì đó ngày hôm nay. Xóa có một kỹ thuật là bình thường. Nếu đối tượng thực sự bị xóa thì bạn sẽ nhận được 404 không tìm thấy nên máy chủ sẽ có cùng trạng thái nhưng phản hồi sẽ khác. Xem hình ảnh con bò: restapitutorial.com/lessons/idempotency.html
JPK

131

Mọi người đều đúng: gắn bó với POST cho các yêu cầu không phải là idempotent.

Còn việc sử dụng cả chuỗi truy vấn URI và nội dung yêu cầu thì sao? Chà, HTTP hợp lệ (xem chú thích 1), vậy tại sao không?!

Nó cũng hoàn toàn hợp lý: URL, bao gồm cả phần chuỗi truy vấn của chúng, để định vị tài nguyên. Trong khi đó các động từ phương thức HTTP (POST - và nội dung yêu cầu tùy chọn của nó) là để chỉ định các hành động hoặc phải làm gì với tài nguyên. Những người nên được quan tâm trực giao. (Nhưng, chúng không phải là mối quan tâm trực giao đẹp cho trường hợp đặc biệt của ContentType = application / x-www-form-urlencoding, xem ghi chú 2 bên dưới.)

Lưu ý 1: Đặc tả HTTP (1.1) không nêu rõ các tham số và nội dung truy vấn là loại trừ lẫn nhau cho máy chủ HTTP chấp nhận các yêu cầu POST hoặc PUT. Vì vậy, bất kỳ máy chủ là miễn phí để chấp nhận cả hai. Tức là nếu bạn viết máy chủ thì không có gì ngăn bạn chọn chấp nhận cả hai (ngoại trừ có thể là một khung không linh hoạt). Nói chung, máy chủ có thể diễn giải các chuỗi truy vấn theo bất kỳ quy tắc nào nó muốn. Nó thậm chí có thể diễn giải chúng với logic có điều kiện đề cập đến các tiêu đề khác như Kiểu nội dung, điều này dẫn đến Lưu ý 2:

Lưu ý 2: nếu trình duyệt web là cách chính mà mọi người truy cập vào ứng dụng web của bạn và ứng dụng / x-www-form-urlencoding là Loại nội dung họ đang đăng, thì bạn nên tuân theo các quy tắc cho Loại nội dung đó. Và các quy tắc cho application / x-www-form-urlencoding cụ thể hơn nhiều (và thẳng thắn, không bình thường): trong trường hợp này, bạn phải hiểu URI là một tập các tham số chứ không phải là một vị trí tài nguyên. [Đây là cùng một điểm hữu ích mà Powerlord nêu ra; rằng có thể khó sử dụng các biểu mẫu web để POST nội dung lên máy chủ của bạn. Chỉ cần giải thích một chút khác nhau.]

Lưu ý 3: chuỗi truy vấn ban đầu để làm gì? RFC 3986 định nghĩa các chuỗi truy vấn HTTP là một phần URI hoạt động như một cách định vị tài nguyên không phân cấp.

Trong trường hợp người đọc hỏi câu hỏi này muốn hỏi kiến ​​trúc RESTful tốt là gì: mẫu kiến ​​trúc RESTful không yêu cầu các lược đồ URI để làm việc theo một cách cụ thể. Kiến trúc RESTful liên quan đến các thuộc tính khác của hệ thống, như khả năng lưu trữ tài nguyên, thiết kế tài nguyên (hành vi, khả năng và biểu diễn của chúng) và liệu có thể thỏa mãn được không. Hay nói cách khác, đạt được một thiết kế tương thích cao với giao thức HTTP và bộ động từ phương thức HTTP. :-) (Nói cách khác, kiến ​​trúc RESTful không được định sẵn nhiều với cách các tài nguyên được định vị .)

Lưu ý cuối cùng: đôi khi các tham số truy vấn được sử dụng cho những thứ khác, không định vị tài nguyên cũng không mã hóa nội dung. Bạn đã bao giờ thấy một tham số truy vấn như 'PUT = true' hoặc 'POST = true' chưa? Đây là cách giải quyết cho các trình duyệt không cho phép bạn sử dụng các phương thức PUT và POST. Trong khi các thông số như vậy được coi là một phần của chuỗi truy vấn URL (trên dây), tôi cho rằng họ không nằm trong truy vấn của URL trong tinh thần .


66

Bạn muốn lý do? Đây là một:

Không thể sử dụng một biểu mẫu web để gửi yêu cầu đến một trang sử dụng kết hợp GET và POST. Nếu bạn đặt phương thức của biểu mẫu thành GET, tất cả các tham số đều nằm trong chuỗi truy vấn. Nếu bạn đặt phương thức của biểu mẫu thành POST, tất cả các tham số đều nằm trong thân yêu cầu.

Nguồn: tiêu chuẩn HTML 4.01, phần 17.13 Gửi mẫu


10
Đó là một lý lẽ hợp lý, nhưng tôi nghĩ loại triển khai Javascript của trình duyệt hiện đại làm cho nó trở thành một điểm chính. Tôi sẽ nghĩ về nó mặc dù - nó hấp dẫn theo một cách chứng minh trong tương lai. Chỉ vì tôi không sử dụng một hình thức cho nó bây giờ không có nghĩa là tôi sẽ không muốn sau này.
Steven Huwig

9
Trộn GET với POST chỉ là một ý tưởng thực sự tồi tệ - phá vỡ khủng khiếp HTTP và không có lý do chính đáng.
aehlke

6
Đoạn trích đó không xuất hiện trên trang bạn liên kết đến
Gareth

40
Đúng, nhưng thuộc tính phương thức chỉ định nghĩa cách "tập dữ liệu biểu mẫu" được bao gồm trong yêu cầu. Khi methodlà POST, không có đề cập đến việc thay đổi URI trong biểu mẫu action. Và bất kỳ URI nào tất nhiên đều có thể chứa một phần chuỗi truy vấn.
Gareth

16
@Powerlord Điều này chỉ sai. Hãy thử thiết lập một biểu mẫu để POST với một hành động ví dụ. /Books?bookCode=1234. Máy chủ web sẽ nhận được các vars dạng POST và một chuỗi truy vấn.
Jez

9

Từ quan điểm lập trình, đối với khách hàng, nó đóng gói các tham số và gắn chúng vào url và thực hiện POST so với GET. Về phía máy chủ, nó đánh giá các tham số gửi đến từ chuỗi truy vấn thay vì các byte được đăng. Về cơ bản, nó là một rửa.

Trường hợp có thể có những lợi thế / bất lợi có thể là cách các nền tảng máy khách cụ thể hoạt động với các thói quen POST và GET trong ngăn xếp mạng của họ, cũng như cách máy chủ web xử lý các yêu cầu đó. Tùy thuộc vào việc thực hiện của bạn, một cách tiếp cận có thể hiệu quả hơn cách tiếp cận khác. Biết rằng sẽ hướng dẫn quyết định của bạn ở đây.

Tuy nhiên, từ quan điểm của một lập trình viên, tôi thích cho phép POST với tất cả các tham số trong thân hoặc GET với tất cả các tham số trên url và bỏ qua các tham số url với bất kỳ yêu cầu POST nào. Nó tránh nhầm lẫn.


8

Tôi nghĩ rằng vẫn có thể khá RESTful khi có các đối số truy vấn xác định tài nguyên trên URL trong khi vẫn giữ tải trọng nội dung giới hạn trong phần thân POST. Điều này dường như tách biệt các cân nhắc của "Tôi đang gửi cái gì?" so với "Tôi đang gửi nó cho ai?".


5
Câu hỏi không phải là về REST.
Steven Huwig

3
@ user359996 Không phải tất cả các API HTTP đều RESTful. Trên thực tế, hầu hết các API tuyên bố rằng thực tế không có. Ngoài ra, thực tế thú vị, REST cũng không chỉ HTTP.
Alec Mev

4

Các REST của trại có một số nguyên tắc hướng dẫn mà chúng ta có thể sử dụng để tiêu chuẩn hóa cách chúng ta sử dụng HTTP động từ. Điều này hữu ích khi xây dựng API RESTful như bạn đang làm.

Tóm lại: GET nên được đọc Chỉ có nghĩa là không có ảnh hưởng đến trạng thái máy chủ. POST được sử dụng để tạo tài nguyên trên máy chủ. PUT được sử dụng để cập nhật hoặc tạo tài nguyên. XÓA được sử dụng để xóa một tài nguyên.

Nói cách khác, nếu hành động API của bạn thay đổi trạng thái máy chủ, REST khuyên chúng tôi sử dụng POST / PUT / DELETE, nhưng không NHẬN.

Tác nhân người dùng thường hiểu rằng thực hiện nhiều POST là xấu và sẽ cảnh báo chống lại nó, bởi vì mục đích của POST là thay đổi trạng thái máy chủ (ví dụ: trả tiền cho hàng hóa khi thanh toán) và bạn có thể không muốn làm điều đó hai lần!

So sánh với một GET mà bạn có thể làm thường xuyên như bạn muốn (idempotent).


13
Trại REST nói rằng bạn nên sử dụng HTTP như được định nghĩa trong thông số HTTP. tức là RFC2616 Không hơn, không kém.
Darrel Miller

1
@Darrel Giới thiệu ibm.com/developerworks/webservice/l Library / ws-restful : REST yêu cầu các nhà phát triển sử dụng các phương thức HTTP một cách rõ ràng và theo cách phù hợp với định nghĩa giao thức. Nguyên tắc thiết kế REST cơ bản này thiết lập ánh xạ một-một giữa các hoạt động tạo, đọc, cập nhật và xóa (CRUD) và các phương thức HTTP. Theo ánh xạ này: Để tạo tài nguyên trên máy chủ, hãy sử dụng POST. Để lấy tài nguyên, sử dụng GET. Để thay đổi trạng thái của tài nguyên hoặc cập nhật nó, hãy sử dụng PUT. Để xóa hoặc xóa tài nguyên, sử dụng XÓA.
buồm

5
Xin lỗi nhưng điều đó hoàn toàn sai. REST yêu cầu tuân thủ một giao diện thống nhất. Nếu bạn đang sử dụng HTTP thì giao diện thống nhất đó được xác định một phần bởi RFC 2616. Trong thông số đó, không có ánh xạ một-một giữa tạo, đọc, cập nhật và xóa và các phương thức HTTP.
Darrel Miller

3
NHẬN và XÓA bản đồ khá tốt để đọc và xóa trong CRUD, nhưng sử dụng PUT / POST để cập nhật và tạo không đơn giản như vậy. Xem stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw

5
Nhìn lại điều này 6 năm sau, và cho rằng câu hỏi đã được xem ~ 100 nghìn lần, tôi cảm thấy giá trị của nó trong một bản cập nhật nhỏ. Darrel đúng theo định nghĩa của Fielding về REST ( ics.uci.edu/~fielding/pub/dissertation/rest_arch_style.htmlm ) - không có đề cập đến việc ánh xạ các động từ HTTP sang CRUD. Lời khuyên dành cho nhà phát triển của IBM (liên kết trong nhận xét ở trên) phản ánh thực tiễn phổ biến trong việc triển khai API của RESTful, chứ không phải định nghĩa về REST của Fielding.
thuyền

-13

Tôi đồng ý - có thể an toàn hơn khi sử dụng yêu cầu GET nếu bạn chỉ truyền dữ liệu trong URL chứ không phải trong cơ thể. Xem câu hỏi tương tự này để biết một số quan điểm bổ sung về toàn bộ khái niệm POST + GET.


17
Nếu hoạt động có tác dụng phụ, thì chắc chắn sẽ không 'an toàn' hơn khi sử dụng phương thức GET vì trình duyệt cho rằng tất cả các GET đều không hoạt động.
dcstraw

Các công cụ tìm kiếm cũng chuyển đổi điều đó trong một cơn ác mộng, vì Google sẽ "nhấp" một cách an toàn tất cả các liên kết với yêu cầu GET, nhưng sẽ bỏ qua mọi thứ khác. Sẽ không an toàn khi để một dịch vụ mà trình thu thập thông tin vô tội có thể vô tình xóa sạch cơ sở dữ liệu.
Alejandro
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.