Jak mogę sobie poradzić z ograniczeniami długości ciągu zapytania HTTP GET i nadal chcę, aby był zgodny z REST?

84

Jak podano w http://www.boutell.com/newfaq/misc/urllength.html , ciąg zapytania HTTP ma ograniczoną długość. Może być ograniczona przez klienta (Firefox, IE, ...), serwer (Apache, IIS, ...) lub sprzęt sieciowy (aplikacyjna zapora, ...).

Dziś mam ten problem z formularzem wyszukiwania. Opracowaliśmy formularz wyszukiwania z wieloma polami, który jest wysyłany na serwer jako żądanie GET, więc mogę dodać zakładkę do wynikowej strony.

Mamy tak wiele pól, że nasz ciąg zapytania ma 1100 bajtów i mamy zaporę ogniową, która odrzuca żądania HTTP GET z więcej niż 1024 bajtami. Nasz administrator systemu zaleca nam zamiast tego używanie POST, aby nie było żadnych ograniczeń.

Jasne, POST zadziała, ale naprawdę czuję wyszukiwanie jako GET, a nie POST. Więc myślę, że przejrzę nasze nazwy pól, aby upewnić się, że ciąg zapytania nie jest zbyt długi, a jeśli nie mogę, będę pragmatyczny i użyję POST.

Ale czy istnieje błąd w projektowaniu usług RESTful? Jeśli mamy ograniczoną długość żądania GET, jak mogę wysłać duże obiekty do usługi sieciowej RESTful? Na przykład, jeśli mam program, który sprawia, że obliczenia oparte na pliku i chcę, aby zapewnić relaksującego usługa takiego: http://compute.com?content=<base64 file>. To nie zadziała, ponieważ ciąg zapytania nie ma nieograniczonej długości.

Jestem trochę zdziwiony ...

cbliard
źródło
2
Co oznacza odpoczynek w kontekście twojego kontekstu? Lub parafrazując: dlaczego GET jest spokojny, a POST nie? Ponieważ GET można skonstruować za pomocą prostej konkatenacji ciągów? Ograniczenie długości zapytania ma na celu uniknięcie dynamicznej alokacji pamięci w aplikacjach, które mają działać szybko.
chaczik
5
Kiedy chcę przeprowadzić wyszukiwanie, nie chcę czegoś tworzyć, usuwać ani aktualizować, chcę tylko odzyskać dane, więc nie powinienem używać POST, DELETE ani PUT, a powinienem użyć GET. Tak właśnie zrozumiałem REST, ale mogę się co do tego
mylić
GET nie nadaje się do wyszukiwania, ponieważ wyniki wyszukiwania mogą się zmieniać w czasie. Infrastruktura internetowa często umożliwia buforowanie żądań GET. Jeśli używasz GET, ryzykujesz uzyskanie starych, nieaktualnych wyników wyszukiwania. POST to sposób, zgodnie z zaleceniami poniżej.
occulus
15
Wszystko zmienia się z biegiem czasu ( en.wikipedia.org/wiki/Impermanence ), taka jest natura wszechświata ... Ale GET powinno być używane do wyszukiwania, ponieważ "akcja wyszukiwania" nie zmienia wyników
Luxspes

Odpowiedzi:

51

Na podstawie twojego opisu IMHO powinieneś użyć POST. POST służy do umieszczania danych na serwerze i, w niektórych przypadkach, uzyskiwania odpowiedzi. W twoim przypadku wykonujesz wyszukiwanie (wysyłasz zapytanie do serwera) i uzyskujesz wynik tego wyszukiwania (odzyskujesz wynik zapytania).

Definicja GET mówi, że należy go użyć do pobrania już istniejącego zasobu. Z definicji POST polega na utworzeniu nowego zasobu. To jest dokładnie to, co robisz: tworzenie zasobu na serwerze i pobieranie go! Nawet jeśli nie przechowujesz wyniku wyszukiwania, utworzyłeś obiekt na serwerze i pobrałeś go. Jak wcześniej powiedział PeterMmm, można to zrobić za pomocą POST (utworzyć i zapisać wynik zapytania), a następnie użyć GET do pobrania zapytania, ale bardziej praktyczne jest wykonanie tylko POST i odzyskanie wyniku.

Mam nadzieję że to pomoże! :)

jmpcm
źródło
2
Masz rację, widzę to jako POST, ponieważ wyszukiwanie jest zmiennym, nowo obliczonym zasobem. Ale nadal mam problemy z dostrzeżeniem granicy między POST i GET. Jeśli chcę przeszukać wszystkie książki science-fiction w bibliotece, otrzymam zbiór istniejących zasobów, więc kusi mnie, aby użyć GET, ale proponujesz, aby zobaczyć go jako POST, ponieważ wyszukiwanie samo w sobie jest nowym zasobem. Zatem ciąg zapytania w GET powinien być używany tylko do zmiany reprezentacji danych, ale nie do filtrowania danych. Czy mam rację?
cbliard
8
POST nie powinien być używany do wyszukiwania, GET jest tym, co powinno być używane, w ten sposób możesz udostępniać i buforować wynikowy adres URL i wyniki, a także lepiej wykorzystywać architekturę RESTful Internetu
Luxspes
37
Ta odpowiedź brzmi bardziej jak próba zabawy słowami. Zgodnie z tą logiką możemy zrobić wszystko jako żądania POST i nadal być RESTful.
supertonsky
9
Ta odpowiedź wydaje się, że rozmawia ze mną jakiś prawnik :-) Pytanie naprawdę brzmi: „Mam sprawę GET, ok. Ale mój ciąg zapytania przekracza dozwoloną długość. Jak sobie z tym poradzić”. Głosowanie na tę odpowiedź.
G. Stoynev
2
Jeśli ta logika była zgodna, to każde żądanie tworzy zasób i pobiera go.
Alex,
66

Specyfikacja HTTP faktycznie zaleca używanie POST podczas wysyłania danych do zasobu w celu obliczenia.

Twoje wyszukiwanie wygląda jak obliczenia, a nie sam zasób. To, co możesz zrobić, jeśli nadal chcesz, aby wyniki wyszukiwania były zasobem, to utworzyć token, aby zidentyfikować ten konkretny wynik wyszukiwania i przekierować klienta użytkownika do tego zasobu.

Po pewnym czasie możesz usunąć tokeny wyników wyszukiwania.

Przykład

POST /search
query=something&category=c1&category=c2&...

201 Created
Location: /search/01543164876

następnie

GET /search/01543164876

200 Ok
... your results here...

W ten sposób przeglądarki i serwery proxy mogą nadal buforować wyniki wyszukiwania, ale przesyłasz parametry zapytania za pomocą POST.

EDYTOWAĆ

Dla wyjaśnienia, 01543164876tutaj reprezentuje unikalny identyfikator zasobu reprezentującego twoje wyszukiwanie. Te 2 żądania zasadniczo oznaczają: utwórz nowy obiekt wyszukiwania z tymi kryteriami, a następnie pobierz wyniki powiązane z utworzonym obiektem wyszukiwania.

Ten identyfikator może być unikalnym identyfikatorem generowanym dla każdego nowego żądania. Oznaczałoby to, że z serwera wycieknie obiekty „wyszukiwania” i będziesz musiał je regularnie czyścić za pomocą strategii buforowania.

Lub może to być skrót wszystkich kryteriów wyszukiwania faktycznie reprezentujących wyszukiwanie zadane przez użytkownika. Pozwala to na ponowne wykorzystanie identyfikatorów, ponieważ ponowne utworzenie wyszukiwania zwróci istniejący identyfikator, który może (ale nie musi) być już zapisany w pamięci podręcznej.

Vincent Robert
źródło
W jaki sposób odnosi się to do wymagań OP dotyczących dodawania zapytania do zakładek?
Rabarbar
2
@Rhubarb rozwiązuje to wyraźnie, tworząc zasób dla danego wyszukiwania.
maulik13
3
Spowolni to wyniki. Wykonaj post, a następnie wykonaj GET. doda co najmniej 300 ms więcej, aby pobrać wyszukiwanie.
jaxxbo
Link do źródła nie działa
Emobe
Jestem zdezorientowany, co robi serwer między POST a GET? czy buforuje dane wyszukiwania na serwerze i po prostu czeka na nadejście żądania GET? Aby to zrobić, musiałby użyć jakiegoś unikalnego identyfikatora, abyś mógł odzyskać pamięć podręczną. Twoja odpowiedź jest ładna, ale na pewno nie pełna. A użycie pamięci podręcznej sprawi, że sytuacja będzie mniej bezpaństwowa.
Alexander Mills,
5

REST to sposób robienia rzeczy, a nie protokół. Nawet jeśli nie lubisz POST, gdy jest to naprawdę GET, zadziała.

Jeśli będziesz / musisz pozostać przy "standardowej" definicji GET, POST, itp., To może rozważyć POST zapytanie, to zapytanie zostanie zapisane na serwerze z identyfikatorem zapytania i zażąda zapytania później za pomocą GET według identyfikatora.

Peter Mmm
źródło
4

Odnośnie twojego przykładu: http://compute.com?content={base64file}użyłbym POST, ponieważ przesyłasz "coś" do obliczenia. Dla mnie to „coś” bardziej przypomina zasób jako prosty parametr.

W przeciwieństwie do tego w zwykłym wyszukiwaniu zacząłbym trzymać się GET i parametrów. Ułatwiasz klientom api testowanie i zabawę z interfejsem API. Uczyń dostęp tylko do odczytu (który w większości przypadków stanowi większość ruchu) tak prostym, jak to tylko możliwe!

Ale dylemat dużych ciągów zapytań jest ważnym ograniczeniem GET. Tutaj postąpiłbym pragmatycznie, o ile nie przekroczysz tego limitu, użyj GET i parametrów url. To zadziała w 98% przypadków wyszukiwania. Działaj tylko wtedy, gdy osiągniesz ten limit, a następnie wprowadź również POST z ładunkiem (z typem mime Content-Type: application/x-www-form-urlencoded).

Czy masz więcej przykładów ze świata rzeczywistego?

manuel aldana
źródło
Obliczenia były prawdziwym przykładem świata. Jeśli chodzi o wyszukiwanie, chcemy mieć możliwość wyszukiwania transakcji w wielu punktach sprzedaży, dlatego otwieramy nowe okno przeglądarki, aby wybrać punkty sprzedaży. A kiedy zatwierdzamy, modyfikujemy ukryty parametr w formularzu wyszukiwania, aby ustawić wybrane punkty sprzedaży. Jeśli jest ich naprawdę wiele, wynikowe żądanie wyszukiwania będzie miało bardzo długi ciąg zapytania.
cbliard
3

Zamieszanie związane z GET to ograniczenie przeglądarki. Jeśli tworzysz interfejs RESTful dla aplikacji A2A lub P2P, nie ma ograniczeń co do długości Twojego GET.

Teraz, jeśli zdarzy ci się użyć przeglądarki, aby wyświetlić interfejs RESTful (aka podczas programowania / debugowania), napotkasz ten limit, ale istnieją narzędzia, które pozwalają obejść ten problem.

ken kranz
źródło
7
„GET to ograniczenie przeglądarki” - jest to również ograniczenie serwera. Znajdziesz wszystkie serwery internetowe egzekwujące limit, a jeśli masz CDN, mogą również wymusić ograniczenie. Użycie innych narzędzi do wykonania żądania nie spowoduje obejścia ograniczeń serwera.
Courtney Miles,
0

To jest proste. Użyj POST. HTTP nie narzuca ograniczenia długości adresu URL dla GET, ale serwery tak. Bądź pragmatyczny i omijaj to za pomocą POST.

Możesz również użyć treści GET (jest to dozwolone), ale jest to podwójna sztuczka, ponieważ nie jest to poprawne użycie i prawdopodobnie spowoduje problemy z serwerem.

Rick O'Shea
źródło