Tworzę nową usługę RESTful dla naszej aplikacji.
Podczas wykonywania GET na niektórych obiektach klienci mogą żądać zawartości tego obiektu. Jeśli chcą dodać niektóre parametry (na przykład sortując listę), mogą dodać te parametry w ciągu zapytania.
Alternatywnie chcę, aby ludzie mogli określić te parametry w treści żądania. HTTP / 1.1 nie wydaje się tego wyraźnie zabraniać. Pozwoli im to określić więcej informacji, może ułatwić określenie złożonych żądań XML.
Moje pytania:
- Czy to w ogóle dobry pomysł?
- Czy klienci HTTP będą mieli problemy z używaniem treści żądania w ramach żądania GET?
Odpowiedzi:
Komentarz Roya Fieldinga dotyczący włączenia ciała z prośbą GET .
Tak, możesz wysłać treść żądania za pomocą GET, ale nie powinno to mieć żadnego znaczenia. Jeśli nadasz mu znaczenie, analizując go na serwerze i zmieniając odpowiedź w oparciu o jego zawartość , wówczas ignorujesz to zalecenie w specyfikacji HTTP / 1.1, sekcja 4.3 :
I opis metody GET w specyfikacji HTTP / 1.1, sekcja 9.3 :
który stwierdza, że ciało żądania nie jest częścią identyfikacji zasobu w żądaniu GET, tylko identyfikator URI żądania.
Aktualizacja RFC2616 określany jako „specyfikacja HTTP / 1.1” jest już nieaktualny. W 2014 r. Został zastąpiony przez RFC 7230-7237. Cytuj „treść wiadomości POWINNA zostać zignorowana podczas obsługi żądania” została usunięta. Teraz jest to po prostu „Żądanie ramkowania wiadomości jest niezależne od semantyki metody, nawet jeśli metoda nie definiuje żadnego zastosowania dla treści wiadomości” Drugi cytat „Metoda GET oznacza pobieranie wszelkich informacji ... zidentyfikowanych przez URI żądania” został usunięty. - Z komentarza
źródło
Chociaż możesz to zrobić, o ile nie jest to wyraźnie wykluczone w specyfikacji HTTP, sugerowałbym unikanie tego tylko dlatego, że ludzie nie oczekują, że coś będzie działać w ten sposób. Łańcuch żądań HTTP składa się z wielu etapów i chociaż „w większości” są one zgodne ze specyfikacją HTTP, jedyną gwarancją jest to, że będą się zachowywać tak, jak zwykle używane są w przeglądarkach internetowych. (Myślę o takich rzeczach, jak przezroczyste proxy, akceleratory, zestawy narzędzi A / V itp.)
Taki jest duch zasady solidności z grubsza „bądź liberalny w tym, co akceptujesz, a konserwatywny w tym, co wysyłasz”, nie chcesz przekraczać granic specyfikacji bez uzasadnionego powodu.
Jeśli jednak masz dobry powód, idź do niego.
źródło
Prawdopodobnie napotkasz problemy, jeśli kiedykolwiek spróbujesz skorzystać z buforowania. Serwery proxy nie będą szukać w treści GET, aby sprawdzić, czy parametry mają wpływ na odpowiedź.
źródło
Ani restclient, ani konsola REST nie obsługują tego, ale curl tak.
Specyfikacja HTTP mówi w sekcji 4.3
Sekcja 5.1.1 przekierowuje nas do sekcji 9.x dla różnych metod. Żaden z nich wyraźnie nie zabrania dołączania treści wiadomości. Jednak...
Sekcja 5.2 mówi
a sekcja 9.3 mówi
Które razem sugerują, że podczas przetwarzania żądania GET serwer nie musi sprawdzać niczego innego niż pole URI żądania i pole nagłówka Host.
Podsumowując, specyfikacja HTTP nie uniemożliwia wysłania treści wiadomości za pomocą GET, ale istnieje wystarczająca dwuznaczność, która nie zaskoczyłaby mnie, gdyby nie była obsługiwana przez wszystkie serwery.
źródło
GET /contacts/100/addresses
Zwraca zbiór adresów dla osoby zid=100
.Elasticsearch akceptuje żądania GET z treścią. Wydaje się nawet, że jest to preferowany sposób: Przewodnik po Elasticsearch
Niektóre biblioteki klienta (np. Sterownik Ruby) mogą rejestrować komendę cry na standardowym wyjściu w trybie programowania i korzysta z tej składni w szerokim zakresie.
źródło
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'
jest równoważne z włączeniem ładunku jakosource
param:curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
To, co próbujesz osiągnąć, zostało zrobione przez długi czas przy użyciu znacznie popularniejszej metody, która nie polega na użyciu ładunku z GET.
Możesz po prostu zbudować swój konkretny mediaty wyszukiwania, lub jeśli chcesz być bardziej RESTful, użyj czegoś takiego jak OpenSearch i WYŚLIJ żądanie do identyfikatora URI, który polecił serwer, powiedz / szukaj. Serwer może następnie wygenerować wynik wyszukiwania lub zbudować końcowy identyfikator URI i przekierować za pomocą 303.
Ma to tę zaletę, że postępuje zgodnie z tradycyjną metodą PRG, pomaga buforować wyniki pośrednikom w pamięci podręcznej itp.
To powiedziawszy, URI są i tak kodowane dla wszystkiego, co nie jest ASCII, podobnie jak application / x-www-form-urlencoded i multipart / form-data. Zalecam użycie tego zamiast tworzenia kolejnego niestandardowego formatu JSON, jeśli masz zamiar obsługiwać scenariusze ReSTful.
źródło
Możesz albo wysłać GET z ciałem, albo wysłać POST i zrezygnować z RESTish religijności (nie jest tak źle, 5 lat temu był tylko jeden członek tej wiary - jego komentarze powyżej).
Nie są to również świetne decyzje, ale wysłanie treści GET może zapobiec problemom niektórych klientów - i niektórych serwerów.
Wykonanie testu POST może napotkać przeszkody w niektórych ramach RESTish.
Julian Reschke zasugerował powyżej, używając niestandardowego nagłówka HTTP, takiego jak „SZUKAJ”, co może być eleganckim rozwiązaniem, z tym wyjątkiem, że jest jeszcze mniej prawdopodobne, że będzie obsługiwane.
Najbardziej wydajne może być wyświetlenie listy klientów, którzy mogą i nie mogą wykonać każdego z powyższych.
Klienci, którzy nie mogą wysłać GET z ciałem (o czym wiem):
Klienci, którzy mogą wysłać GET z treścią:
Serwery i biblioteki, które mogą pobrać ciało z GET:
Serwery (i serwery proxy), które usuwają ciało z GET:
źródło
SEARCH
metoda może się po drodze złamać? Jeśli pełnomocnicy nie rozumieją metody, oczekuje się, że ją przeprowadzą, tak jak jest, więc nie jestem zbyt pewien, dlaczego według ciebie cokolwiek by to zepsuło ...Zadałem to pytanie IGF HTTP WG. Komentarz Roy'a Fieldinga (autora dokumentu http / 1.1 w 1998 r.) Był taki
RFC 7213 (HTTPbis) stwierdza:
Teraz wydaje się jasne, że intencją było, aby znaczenie semantyczne w treściach żądania GET było zabronione, co oznacza, że treść żądania nie może być użyta do wpłynięcia na wynik.
Istnieją serwery proxy, które na pewno złamią twoją prośbę na różne sposoby, jeśli dodasz ciało do GET.
Podsumowując, nie rób tego.
źródło
Google na przykład ma gorsze wyniki niż ignorowanie, uzna to za błąd !
Wypróbuj sam z prostym netcat:
(po zawartości 1234 następuje CR-LF, czyli w sumie 6 bajtów)
a otrzymasz:
Dostajesz także 400 Bad Request od Bing, Apple itp. ... które są obsługiwane przez AkamaiGhost.
Dlatego nie zalecałbym używania żądań GET z jednostką treści.
źródło
GET
żądań, to dlatego, że ich własny serwer niestandardowy jest w stanie to obsłużyć. Pytanie brzmi zatem, czy inne „części ruchome” (przeglądarki, pamięci podręczne itp.) Będą działać poprawnie.GET
konkretnego punktu końcowego - nie ma to nic wspólnego z użyciemGET
w ogólnym przypadku. Losowy ładunek możePOST
równie łatwo zepsuć się i zwrócić to samo400 Bad Request
, jeśli zawartość nie jest w formacie, który ma sens w kontekście konkretnego żądania.Z RFC 2616, sekcja 4.3 , „Treść wiadomości”:
Oznacza to, że serwery powinny zawsze odczytywać wszelkie udostępnione treści żądania z sieci (sprawdzać Długość treści lub odczytywać fragmenty itp.). Ponadto pełnomocnicy powinni przekazywać wszelkie otrzymane przez siebie takie organy wniosku. Następnie, jeśli RFC definiuje semantykę dla treści dla danej metody, serwer może faktycznie użyć treści żądania do wygenerowania odpowiedzi. Jeśli jednak RFC nie definiuje semantyki dla treści, serwer powinien ją zignorować.
Jest to zgodne z cytatem z Fielding powyżej.
Sekcja 9.3 , „GET”, opisuje semantykę metody GET i nie wspomina o treściach żądań. Dlatego serwer powinien zignorować wszelkie treści żądania otrzymane na żądanie GET.
źródło
Według XMLHttpRequest nie jest poprawny. Od standardu :
Chociaż nie sądzę, że powinno tak być, ponieważ żądanie GET może wymagać dużej zawartości treści.
Jeśli więc polegasz na XMLHttpRequest przeglądarki, prawdopodobnie nie będzie działać.
źródło
Jeśli naprawdę chcesz wysłać buforowalną treść JSON / XML do aplikacji internetowej, jedynym rozsądnym miejscem na umieszczenie danych jest ciąg zapytania zakodowany za pomocą RFC4648: kodowanie Base 64 z URL i bezpiecznym alfabetem nazwy pliku . Oczywiście możesz po prostu urlencode JSON i umieścić jest w wartości parametru param URL, ale Base64 daje mniejszy wynik. Pamiętaj, że istnieją ograniczenia rozmiaru adresu URL, zobacz Jaka jest maksymalna długość adresu URL w różnych przeglądarkach? .
Możesz myśleć, że
=
znak dopełniania Base64 może być zły dla wartości param adresu URL, jednak wydaje się, że nie - patrz ta dyskusja: http://mail.python.org/pipermail/python-bugs-list/2007-Feburn/037195.html . Nie należy jednak umieszczać zakodowanych danych bez nazwy parametru, ponieważ zakodowany ciąg z dopełnianiem będzie interpretowany jako klucz parametru z pustą wartością. Użyłbym czegoś takiego?_b64=<encodeddata>
.źródło
Vary
nagłówku nie wiedziałem, że to prawdziwy potencjał.Nie radziłbym tego, jest to sprzeczne ze standardowymi praktykami i nie oferuje tyle w zamian. Chcesz zachować treść, a nie opcje.
źródło
Co z niezgodnymi nagłówkami zakodowanymi w base64? „SOMETHINGAPP-PARAMS: sdfSD45fdg45 / aS”
Ograniczenia długości hm. Czy nie potrafisz rozróżnić znaczeń w procedurze POST? Jeśli chcesz prostych parametrów, takich jak sortowanie, nie rozumiem, dlaczego byłby to problem. Myślę, że martwisz się pewnością.
źródło
x-
prefiksem, wszelkie ograniczenia długości nagłówków byłyby całkowicie ograniczeniem arbitralnym serwera.Jestem zdenerwowany tym, że REST, ponieważ protokół nie obsługuje OOP, a
Get
metoda jest dowodem. Jako rozwiązanie możesz serializować DTO do JSON, a następnie utworzyć ciąg zapytania. Po stronie serwera możesz przekształcić ciąg zapytania do DTO.Spójrz na:
Podejście oparte na wiadomościach może pomóc w rozwiązaniu problemu Ograniczenie metody. Będziesz mógł wysłać dowolne DTO jak w treści żądania
Struktura serwisu internetowego Nelibur zapewnia funkcjonalność, z której można korzystać
źródło
Na przykład działa z Curl, Apache i PHP.
Plik PHP:
Polecenie konsoli:
Wynik:
źródło
$_POST
wtedy, gdy treść zostanie wysłana z żądaniem POST iapplication/x-www-form-urlencoded
. Oznacza to, że ciało jest ignorowane wGET
żądaniu. W tym przypadku:$_GET
i$_POST
w tym momencie bardzo wprowadzają w błąd. Lepsze wykorzystaniephp://input
IMHO możesz po prostu wysłać
JSON
zakodowane (tj.encodeURIComponent
) WURL
ten sposób, aby nie naruszaćHTTP
specyfikacji i dostać sięJSON
na serwer.źródło
Masz listę opcji, które są znacznie lepsze niż używanie treści żądania z GET.
Załóżmy, że masz kategorie i elementy dla każdej kategorii. Oba mają być identyfikowane przez id („catid” / „itemid” na potrzeby tego przykładu). Chcesz sortować według innego parametru „sortuj” w określonym „porządku”. Chcesz przekazać parametry „sortby” i „porządek”:
Możesz:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
Wszystkie mają swoje wady, ale są znacznie lepsze niż używanie GET z ciałem.
źródło
Nawet jeśli popularne narzędzie tego używa, jak często cytowano na tej stronie, myślę, że nadal jest to dość zły pomysł, ponieważ jest zbyt egzotyczny, mimo że nie zabrania tego specyfikacja.
Wiele pośrednich infrastruktur może po prostu odrzucić takie żądania.
Poprzez przykład zapomnieć o korzystaniu z niektórych dostępnych CDN przed swojej stronie internetowej, jak ten jeden :
I tak, biblioteki klienta mogą również nie obsługiwać wysyłania takich żądań, jak opisano w tym komentarzu .
źródło
Korzystam z RestTemplate frameworka Spring w moim programie klienckim i po stronie serwera zdefiniowałem żądanie GET z treścią Json. Mój główny cel jest taki sam jak twój: gdy żądanie ma wiele parametrów, umieszczenie ich w ciele wydaje się bardziej uporządkowane niż umieszczenie ich w przedłużonym ciągu URI. Tak?
Ale niestety to nie działa! Po stronie serwera zgłoszono następujący wyjątek:
org.springframework.http.converter.HttpMessageNotReadableException: Brak wymaganej treści żądania ...
Ale jestem prawie pewien, że treść mojego kodu klienta została poprawnie dostarczona, więc co jest nie tak?
Prześledziłem metodę RestTemplate.exchange () i znalazłem:
Zauważ, że w metodzie executeInternal () argument wejściowy „bufferedOutput” zawiera treść komunikatu dostarczoną przez mój kod. Widziałem to przez debugger.
Jednak z powodu preparConnection () funkcja getDoOutput () w executeInternal () zawsze zwraca false, co z kolei powoduje całkowite zignorowanie bufferedOutput! Nie jest kopiowany do strumienia wyjściowego.
W związku z tym mój program serwera nie otrzymał treści wiadomości i zgłosił ten wyjątek.
To jest przykład RestTemplate frameworka Spring. Chodzi o to, że nawet jeśli treść komunikatu nie jest już zabroniona przez specyfikację HTTP, niektóre biblioteki lub struktury klienta lub serwera mogą nadal być zgodne ze starą specyfikacją i odrzucić treść wiadomości z żądania GET.
źródło