POST HTTP z parametrami zapytania URL - dobry pomysł czy nie? [Zamknięte]

451

Projektuję interfejs API do obsługi protokołu HTTP i zastanawiam się, czy dobrym rozwiązaniem jest użycie polecenia HTTP POST, ale z parametrami zapytań URL i bez treści żądania.

Uwagi:

  • „Dobry projekt internetowy” wymaga wysłania za pomocą POST działań nie idempotentnych. To działanie nie idempotentne.
  • Łatwiej jest rozwijać i debugować tę aplikację, gdy parametry żądania są obecne w adresie URL.
  • Interfejs API nie jest przeznaczony do powszechnego użytku.
  • Wygląda na to, że wykonanie żądania POST bez treści zajmie nieco więcej pracy, np. Content-Length: 0Nagłówek musi zostać wyraźnie dodany.
  • Wydaje mi się również, że test POST bez ciała jest nieco sprzeczny z oczekiwaniami większości programistów i środowisk HTTP.

Czy są jakieś pułapki lub zalety wysyłania parametrów na żądanie POST za pośrednictwem zapytania URL, a nie treści żądania?

Edycja: Powodem tego jest to, że operacje nie są idempotentne i mają skutki uboczne inne niż pobieranie. Zobacz specyfikację HTTP :

W szczególności ustanowiono konwencję, że metody GET i HEAD NIE POWINNY mieć znaczenia innego niż odzyskanie. Metody te należy uznać za „bezpieczne”. Pozwala to agentom użytkownika na reprezentowanie innych metod, takich jak POST, PUT i DELETE, w specjalny sposób, dzięki czemu użytkownik jest informowany o tym, że żądane jest potencjalnie niebezpieczne działanie.

...

Metody mogą również mieć właściwość „idempotence”, ponieważ (oprócz błędów związanych z błędem lub wygasaniem) skutki uboczne N> 0 identycznych żądań są takie same jak w przypadku pojedynczego żądania. Metody GET, HEAD, PUT i DELETE współużytkują tę właściwość. Ponadto metody OPCJE i ŚLEDZENIE NIE POWINNY wywoływać skutków ubocznych, a zatem są z natury idempotentne.

Steven Huwig
źródło
11
Po co w ogóle używać POST, jeśli nie zamierzasz podawać danych w ciele?
Sunny Milenov,
114
Ponieważ operacja nie jest idempotentna.
Steven Huwig
20
@Jared, zauważ, że słowo „REST” nie pojawia się w tym pytaniu sprzed 2,5 roku. :) Specyfikacja HTTP dotycząca idempotencji ma zastosowanie bez względu na to, jak smakuje architektura miesiąca dla usług internetowych. Na szczęście system, dla którego ten interfejs API został zaprojektowany jako serwer proxy, i tak stał się przestarzały.
Steven Huwig,
5
Ponieważ dzienniki serwera nie rejestrują parametrów POST, ale rejestrują ciągi zapytań. O wiele łatwiej jest uruchomić serię żądań bez instrumentowania ich w przeglądarce, a następnie spojrzeć na śledzenie, niż je klikać. Również API nie było przeglądarką między serwerami, ale raczej serwerami. Co najważniejsze, cała sprawa i tak została załatwiona. :)
Steven Huwig
13
Dla każdego, kto nie wie, co oznacza idempotent: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg

Odpowiedzi:

259

Jeśli twoje działanie nie jest idempotentne, MUSISZ użyć POST. Jeśli nie, po prostu prosisz o kłopoty. GET, PUTa DELETEmetody są muszą być idempotentne. Wyobraź sobie, co by się stało w Twojej aplikacji, gdyby klient pobierał wszystkie możliwe GETżądania dotyczące Twojej usługi - jeśli spowodowałoby to widoczne skutki uboczne dla klienta, coś jest nie tak.

Zgadzam się, że wysyłanie ciągu POSTzapytania, ale bez treści, wydaje się dziwne, ale myślę, że może być odpowiednie w niektórych sytuacjach.

Pomyśl o części zapytania w adresie URL jako o poleceniu do zasobu, aby ograniczyć zakres bieżącego żądania. Zazwyczaj ciągi zapytania są używane do sortowania lub filtrowania GETżądania (jak ?page=1&sort=title), ale przypuszczam, że sensowne jest POSTrównież ograniczenie zakresu (być może jak ?action=delete&id=5).

Don McCaughey
źródło
4
Wybrałem tę odpowiedź dla tego konkretnego przypadku, ale myślę, że argument R. Bemrose'a jest przekonujący dla publicznych interfejsów API.
Steven Huwig
4
Nie sądzę, aby jego odpowiedź była całkowicie poprawna. Jeśli znasz parametry adresu URL formularza, gdy strona HTML jest wysyłana do klienta, możesz przypisać te parametry adresu URL do atrybutu akcji formularza, w przeciwnym razie JavaScript może ustawić parametry adresu URL po przesłaniu formularza.
Don McCaughey,
3
co powiesz na wpis pliku xml na adres URL z parametrami zapytania? czy to jest możliwe?
OpenCoderX
3
Kolejny przykład: dane żądania mogą znajdować się w jednostce http, a żądany format odpowiedzi jest przekazywany w parametrze zapytania ( /action?response_format=json)
rds
4
+1 dowiedziałem się dzisiaj. Technika usuwania ma charakter idempotentny. Jeśli obiekt zostanie faktycznie usunięty, otrzymasz 404 nie znaleziony, więc serwer będzie miał ten sam stan, ale odpowiedź będzie inna. Zobacz zdjęcie krowy: restapitutorial.com/lessons/idempotency.html
JPK
131

Wszyscy mają rację: trzymaj się POST dla nie idempotentnych żądań.

Co z użyciem zarówno ciągu zapytania URI, jak i treści żądania? To poprawny HTTP (patrz uwaga 1), więc czemu nie ?!

Jest to również całkowicie logiczne: adresy URL, w tym część ciągu zapytania, służą do lokalizowania zasobów. Natomiast czasowniki metody HTTP (POST - i opcjonalna treść żądania) służą do określania działań lub sposobu postępowania z zasobami. Powinny to być obawy ortogonalne. (Ale nie są to pięknie ortogonalne obawy dotyczące specjalnego przypadku ContentType = application / x-www-form-urlencoded, patrz uwaga 2 poniżej.)

Uwaga 1: Specyfikacja HTTP (1.1) nie określa, że ​​parametry i treść zapytania wykluczają się wzajemnie dla serwera HTTP, który przyjmuje żądania POST lub PUT. Tak więc każdy serwer może zaakceptować oba. Tzn. Jeśli napiszesz serwer, nic nie stoi na przeszkodzie, abyś zaakceptował oba (z wyjątkiem może nieelastycznego frameworka). Zasadniczo serwer może interpretować ciągi zapytań zgodnie z dowolnymi regułami. Może nawet interpretować je za pomocą logiki warunkowej, która odnosi się również do innych nagłówków, takich jak Content-Type, co prowadzi do uwagi 2:

Uwaga 2: jeśli przeglądarka internetowa jest podstawowym sposobem, w jaki ludzie uzyskują dostęp do twojej aplikacji internetowej, a application / x-www-form-urlencoded jest typem treści, który publikują, powinieneś postępować zgodnie z zasadami dla tego typu treści. A zasady dla application / x-www-form-urlencoded są znacznie bardziej szczegółowe (i szczerze mówiąc, niezwykłe): w tym przypadku musisz interpretować URI jako zestaw parametrów, a nie lokalizację zasobu. [Jest to ten sam punkt przydatności podniesiony przez Władcę; korzystanie z formularzy internetowych do wysyłania treści na serwer może być trudne. Wyjaśniłem trochę inaczej.]

Uwaga 3: po co są pierwotnie ciągi zapytań? RFC 3986 definiuje ciągi zapytania HTTP jako część URI, która działa jako niehierarchiczny sposób lokalizowania zasobu.

W przypadku, gdy czytelnicy zadający to pytanie chcą zapytać, co jest dobre architektura RESTful: wzorzec architektury RESTful nie wymaga, aby schematy URI działały w określony sposób. Architektura RESTful dotyczy innych właściwości systemu, takich jak buforowanie zasobów, projektowanie samych zasobów (ich zachowanie, możliwości i reprezentacje) oraz to, czy idempotencja jest spełniona. Innymi słowy, osiągnięcie projektu wysoce kompatybilnego z protokołem HTTP i zestawem czasowników metod HTTP. :-) (Innymi słowy, relaksującego architektura nie jest bardzo presciptive z przebiegu zasobów znajduje ).

Uwaga końcowa: czasami parametry zapytania są wykorzystywane do jeszcze innych rzeczy, które nie są ani lokalizowaniem zasobów, ani kodowaniem treści. Widziałeś kiedyś parametr zapytania, taki jak „PUT = true” lub „POST = true”? Są to obejścia dla przeglądarek, które nie pozwalają na stosowanie metod PUT i POST. Chociaż takie parametry są postrzegane jako część ciągu zapytania adresu URL (w sieci), twierdzę, że nie są one częścią zapytania adresu URL w duchu .

Tim Lovell-Smith
źródło
66

Chcesz powodów? Tutaj jest jeden:

Formularza internetowego nie można użyć do wysłania żądania do strony, która korzysta z kombinacji GET i POST. Jeśli ustawisz metodę formularza na GET, wszystkie parametry znajdują się w ciągu zapytania. Jeśli ustawisz metodę formularza na POST, wszystkie parametry znajdują się w treści żądania.

Źródło: standard HTML 4.01, sekcja 17.13 Przesyłanie formularzy

Władca
źródło
10
To niezły argument, ale myślę, że implementacje JavaScript w nowoczesnej przeglądarce sprawiają, że jest to kwestia sporna. Zastanowię się jednak - jest to przekonujące w sposób przyszłościowy. To, że nie używam teraz formularza, nie oznacza, że ​​nie będę tego chciał później.
Steven Huwig
9
Mieszanie GET z POST to po prostu zły pomysł - straszne zerwanie HTTP i nie bez powodu.
aehlke,
6
Ten fragment nie pojawia się na stronie, do której
linkujesz
40
Zgadza się, ale atrybut metody po prostu określa, w jaki sposób „zestaw danych formularza” jest uwzględniany w żądaniu. Gdy methodjest POST, nie ma wzmianki o zmianie identyfikatora URI w formularzu action. I oczywiście każdy identyfikator URI może już zawierać część ciągu zapytania.
Gareth
16
@Powerlord To po prostu źle. Spróbuj skonfigurować formularz do POST z działaniem np. /Books?bookCode=1234. Serwer WWW otrzyma zmienne formularza POST i ciąg zapytania.
Jez
9

Z programowego punktu widzenia, dla klienta pakuje parametry i dołącza je do adresu URL i przeprowadza test POST vs. GET. Po stronie serwera ocenia parametry przychodzące z kwerendy zamiast wysyłanych bajtów. Zasadniczo jest to pranie.

Mogą występować zalety / wady w sposobie działania określonych platform klienckich z procedurami POST i GET w stosie sieci, a także w sposobie, w jaki serwer WWW radzi sobie z tymi żądaniami. W zależności od implementacji jedno podejście może być bardziej wydajne niż drugie. Wiedząc, że to pomoże ci podjąć decyzję tutaj.

Niemniej jednak, z perspektywy programisty, wolę zezwolić na POST ze wszystkimi parametrami w ciele lub GET ze wszystkimi parametrami na adresie URL, i jawnie ignoruję parametry adresu URL przy każdym żądaniu POST. Pozwala uniknąć zamieszania.

jro
źródło
8

Wydaje mi się, że nadal może być dość RESTful mieć argumenty zapytania, które identyfikują zasób w adresie URL, utrzymując ładunek zawartości ograniczony do treści POST. Wydaje się, że to rozdziela rozważania „Co ja wysyłam?” kontra „Do kogo to wysyłam?”.

swizzcheez
źródło
5
Pytanie nie dotyczyło REST.
Steven Huwig
3
@ user359996 Nie wszystkie interfejsy API HTTP są RESTful. W rzeczywistości większość interfejsów API, które twierdzą, że tak nie jest. Ciekawostką jest, że REST to nie tylko HTTP.
Alec Mev,
4

REST obóz pewne zasady przewodnie, które możemy wykorzystać w celu ujednolicenia sposobu używamy czasowników HTTP. Jest to pomocne podczas budowania interfejsów API RESTful podczas pracy.

W skrócie: GET powinien być tylko do odczytu, tzn. Nie ma wpływu na stan serwera. POST służy do tworzenia zasobu na serwerze. PUT służy do aktualizacji lub utworzenia zasobu. DELETE służy do usuwania zasobu.

Innymi słowy, jeśli działanie API zmienia stan serwera, REST zaleca nam użycie POST / PUT / DELETE, ale nie GET.

Programy klienckie zwykle rozumieją, że wykonywanie wielu testów POST jest złe i ostrzega przed tym, ponieważ celem testu POST jest zmiana stanu serwera (np. Płacenie za towary przy kasie) i prawdopodobnie nie chcesz tego robić dwa razy!

Porównaj z GET, który możesz robić często, jak chcesz (idempotent).

żagiel
źródło
13
Obóz REST mówi, że powinieneś używać HTTP zgodnie ze specyfikacją HTTP. tj. RFC2616 Nic więcej, nic mniej.
Darrel Miller,
1
@Darrel Refering ibm.com/developerworks/webservices/library/ws-restful : REST prosi programistów o jawne użycie metod HTTP w sposób zgodny z definicją protokołu. Ta podstawowa zasada projektowania REST ustanawia mapowanie jeden na jeden między operacjami tworzenia, odczytu, aktualizacji i usuwania (CRUD) a metodami HTTP. Zgodnie z tym odwzorowaniem: Aby utworzyć zasób na serwerze, użyj POST. Aby pobrać zasób, użyj GET. Aby zmienić stan zasobu lub zaktualizować go, użyj PUT. Aby usunąć lub usunąć zasób, użyj DELETE.
żeglowanie
5
Przepraszam, ale to po prostu źle. REST wymaga zgodności z jednolitym interfejsem. Jeśli używasz HTTP, ten jednolity interfejs jest częściowo zdefiniowany przez RFC 2616. W tej specyfikacji nie ma mapowania jeden na jeden między metodami tworzenia, odczytu, aktualizacji i usuwania a metodami HTTP.
Darrel Miller
3
GET i DELETE całkiem dobrze odwzorowują do odczytu i usuwania w CRUD, ale użycie PUT / POST do aktualizacji i tworzenia nie jest tak proste. Zobacz stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw
5
Patrząc wstecz na to 6 lat później i biorąc pod uwagę, że pytanie zostało obejrzane ~ 100 000 razy, uważam, że warto wprowadzić małą aktualizację. Darrel jest poprawny zgodnie z definicją REST Fieldinga ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - nie ma wzmianki o mapowaniu czasowników HTTP na CRUD. Porady IBM dla deweloperów (link w komentarzu powyżej) odzwierciedlają powszechną praktykę we wdrażaniu API RESTful, a nie definicję REST Fieldinga.
żeglowanie
-13

Zgadzam się - prawdopodobnie bezpieczniej jest używać żądania GET, jeśli tylko przekazujesz dane w adresie URL, a nie w treści. Zobacz to podobne pytanie, aby uzyskać dodatkowe informacje na temat całej koncepcji POST + GET.

Marc Nowakowski
źródło
17
Jeśli operacja ma skutki uboczne, użycie metody GET na pewno nie jest „bezpieczniejsze”, ponieważ przeglądarka zakłada, że ​​wszystkie GET są idempotentne.
dcstraw 12.10.11
Wyszukiwarki również przekonwertują to w koszmarze, ponieważ Google bezpiecznie „kliknie” wszystkie linki za pomocą żądania GET, ale pominie wszystko inne. Opuszczenie usługi nie jest tak bezpieczne, że niewinny robot może przypadkowo wyczyścić bazę danych.
Alejandro