Z bardzo prostą semantyką buforowania: jeśli parametry są takie same (a adres URL jest taki sam), to jest to strzał w dziesiątkę. Czy to jest możliwe? Zalecana?
Z bardzo prostą semantyką buforowania: jeśli parametry są takie same (a adres URL jest taki sam), to jest to strzał w dziesiątkę. Czy to jest możliwe? Zalecana?
Odpowiedzi:
Odpowiedni dokument RFC 2616 w sekcji 9.5 (POST) pozwala na buforowanie odpowiedzi na wiadomość POST, jeśli używasz odpowiednich nagłówków.
Odpowiedzi na tę metodę nie podlegają buforowaniu, chyba że odpowiedź zawiera odpowiednie pola nagłówka Cache-Control lub Expires. Jednak odpowiedź 303 (Zobacz inne) może służyć do skierowania agenta użytkownika do pobrania zasobu buforowanego.
Należy pamiętać, że sama RFC stwierdza wyraźnie w punkcie 13 (buforowanie w HTTP), że cache musi unieważnić odpowiednią jednostkę po POST żądanie .
Niektóre metody HTTP MUSZĄ powodować, że pamięć podręczna unieważnia jednostkę. Jest to jednostka, do której odwołuje się identyfikator URI żądania albo nagłówki Location lub Content-Location (jeśli są obecne). Te metody to:
- PUT - DELETE - POST
Nie jest dla mnie jasne, w jaki sposób te specyfikacje mogą pozwolić na znaczące buforowanie.
Zostało to również odzwierciedlone i dokładniej wyjaśnione w RFC 7231 (sekcja 4.3.3.), Który zastępuje RFC 2616.
Odpowiedzi na żądania POST można
zapisywać w pamięci podręcznej tylko wtedy, gdy zawierają wyraźne informacje o aktualności (patrz sekcja 4.2.1 w [RFC7234]).
Jednak buforowanie POST nie jest powszechnie stosowane. W przypadkach, gdy serwer pochodzenia życzy sobie, aby klient mógł buforować wynik POST w sposób, który może być ponownie wykorzystany przez późniejszy GET, serwer pochodzenia MOŻE wysłać odpowiedź 200 (OK) zawierającą wynik i lokalizację zawartości pole nagłówka, które ma taką samą wartość jak efektywny identyfikator URI żądania POST (sekcja 3.1.4.2).
Zgodnie z tym, wynik buforowanego testu POST (jeśli serwer wskaże taką możliwość) może być następnie wykorzystany jako wynik żądania GET dla tego samego URI.
Zgodnie z RFC 2616 sekcja 9.5:
„Odpowiedzi na metodę POST nie podlegają buforowaniu, JEŚLI odpowiedź zawiera odpowiednie pola nagłówka Cache-Control lub Expires”.
Więc TAK, możesz buforować odpowiedź na żądanie POST, ale tylko wtedy, gdy nadejdzie z odpowiednimi nagłówkami. W większości przypadków nie chcesz buforować odpowiedzi. Ale w niektórych przypadkach - na przykład jeśli nie zapisujesz żadnych danych na serwerze - jest to całkowicie właściwe.
Należy jednak pamiętać, że wiele przeglądarek, w tym aktualna Firefox 3.0.10, nie buforuje odpowiedzi POST niezależnie od nagłówków. IE zachowuje się pod tym względem inteligentniej.
Teraz chcę wyjaśnić tutaj pewne zamieszanie dotyczące RFC 2616 S. 13.10. Metoda POST na URI nie „unieważnia zasobu do buforowania”, jak niektórzy tutaj stwierdzili. Powoduje, że poprzednio zbuforowana wersja tego identyfikatora URI jest przestarzała, nawet jeśli jej nagłówki kontroli pamięci podręcznej wskazywały na świeżość i dłuższy czas trwania.
GET
i POST
. Jeśli jesteś pamięcią podręczną znajdującą się między klientem a serwerem, widzisz GET /foo
i buforujesz odpowiedź. Następny widzisz POST /foo
to jesteś zobowiązany do unieważnienia pamięci podręcznej odpowiedź od GET /foo
nawet jeżeli POST
odpowiedź nie zawiera żadnych nagłówków kontroli cache ponieważ są one takie same URI , więc następny GET /foo
będzie musiał revalidate nawet jeśli oryginalne nagłówki wskazane cache będzie nadal na żywo (jeśli nie widziałeś POST /foo
prośby)
But in some cases - such as if you are not saving any data on the server - it's entirely appropriate.
. Jaki jest zatem sens takiego API POST w pierwszej kolejności?
Ogólny:
Zasadniczo POST nie jest idempotentną operacją . Nie możesz więc używać go do buforowania. GET powinna być operacją idempotentną, więc jest powszechnie używana do buforowania.
Zobacz sekcję 9.1 protokołu HTTP 1.1 RFC 2616 S. 9.1 .
Poza semantyką metody GET:
Sama metoda POST jest semantycznie przeznaczona do wysyłania czegoś do zasobu. POST nie może być buforowany, ponieważ jeśli zrobisz coś raz, dwa razy vs trzy razy, za każdym razem zmieniasz zasoby serwera. Każde żądanie ma znaczenie i powinno zostać dostarczone na serwer.
Sama metoda PUT jest semantycznie przeznaczona do umieszczania lub tworzenia zasobu. Jest to operacja idempotentna, ale nie będzie używana do buforowania, ponieważ w międzyczasie mogło nastąpić DELETE.
Sama metoda DELETE jest semantycznie przeznaczona do usuwania zasobu. Jest to operacja idempotentna, ale nie będzie używana do buforowania, ponieważ w międzyczasie mogło dojść do PUT.
Odnośnie buforowania po stronie klienta:
Przeglądarka internetowa zawsze przekaże Twoje żądanie, nawet jeśli otrzyma odpowiedź z poprzedniej operacji POST. Na przykład możesz wysyłać e-maile za pomocą Gmaila w odstępie kilku dni. Mogą mieć ten sam temat i treść, ale należy wysłać oba e-maile.
Odnośnie buforowania proxy:
Serwer proxy HTTP, który przekazuje Twoją wiadomość do serwera, nigdy nie buforowałby niczego poza żądaniem GET lub HEAD.
Odnośnie buforowania serwera:
Serwer domyślnie nie obsługiwałby automatycznie żądania POST poprzez sprawdzanie swojej pamięci podręcznej. Ale oczywiście żądanie POST może zostać wysłane do twojej aplikacji lub dodatku i możesz mieć własną pamięć podręczną, z której odczytujesz, gdy parametry są takie same.
Unieważnienie zasobu:
Sprawdzenie protokołu HTTP 1.1 RFC 2616 S. 13.10 pokazuje, że metoda POST powinna unieważnić zasób do buforowania.
Jeśli buforujesz odpowiedź POST, musi ona być skierowana do aplikacji internetowej. To właśnie oznacza „Odpowiedzi na tę metodę nie mogą być buforowane, chyba że odpowiedź zawiera odpowiednie pola nagłówka Cache-Control lub Expires”.
Można spokojnie założyć, że aplikacja, która wie, czy wyniki testu POST są idempotentne, decyduje o dołączeniu niezbędnych i odpowiednich nagłówków kontroli pamięci podręcznej. Jeśli nagłówki sugerujące, że buforowanie jest dozwolone, są obecne, aplikacja informuje cię, że POST jest w rzeczywistości super-GET; że użycie POST było wymagane tylko ze względu na ilość niepotrzebnych i nieistotnych (ze względu na użycie URI jako klucza pamięci podręcznej) danych niezbędnych do wykonania idempotentnej operacji.
Przy tym założeniu następujące GET-y mogą być obsługiwane z pamięci podręcznej.
Aplikacja, której nie udało się dołączyć niezbędnych i poprawnych nagłówków w celu rozróżnienia między buforowanymi i niepodlegającymi buforowaniu odpowiedziami POST, jest winna wszelkich nieprawidłowych wyników buforowania.
To powiedziawszy, każdy POST, który trafia do pamięci podręcznej, wymaga weryfikacji przy użyciu warunkowych nagłówków. Jest to wymagane, aby odświeżyć zawartość pamięci podręcznej, aby wyniki testu POST nie były odzwierciedlane w odpowiedziach na żądania do czasu wygaśnięcia okresu istnienia obiektu.
Mark Nottingham przeanalizował, kiedy można buforować odpowiedź testu POST. Zauważ, że kolejne żądania, które chcą skorzystać z buforowania, muszą być żądaniami GET lub HEAD. Zobacz także semantykę http
POST nie zajmują się reprezentacjami określonego stanu, 99 razy na 100. Jest jednak jeden przypadek, w którym tak się dzieje; gdy serwer robi wszystko, aby powiedzieć, że ta odpowiedź POST jest reprezentacją jego URI, ustawiając nagłówek Content-Location, który jest taki sam jak identyfikator URI żądania. W takim przypadku odpowiedź POST jest podobna do odpowiedzi GET na ten sam identyfikator URI; może być buforowany i ponownie używany - ale tylko w przypadku przyszłych żądań GET.
Jeśli zastanawiasz się, czy możesz zapisać w pamięci podręcznej żądanie posta i spróbować znaleźć odpowiedź na to pytanie, prawdopodobnie nie odniesiesz sukcesu. Podczas wyszukiwania „żądania publikacji w pamięci podręcznej” pierwszym wynikiem jest pytanie StackOverflow.
Odpowiedzi są zagmatwaną mieszanką tego, jak powinno działać buforowanie, jak działa buforowanie zgodnie z RFC, jak buforowanie powinno działać zgodnie z RFC i jak działa buforowanie w praktyce. Zacznijmy od RFC, zobaczmy, jak faktycznie działa przeglądarka, a następnie porozmawiajmy o sieciach CDN, GraphQL i innych problematycznych obszarach.
Zgodnie z RFC, żądania POST muszą unieważniać pamięć podręczną:
13.10 Invalidation After Updates or Deletions
..
Some HTTP methods MUST cause a cache to invalidate an entity. This is
either the entity referred to by the Request-URI, or by the Location
or Content-Location headers (if present). These methods are:
- PUT
- DELETE
- POST
Ten język sugeruje, że żądania POST nie mogą być buforowane, ale to nieprawda (w tym przypadku). Pamięć podręczna jest unieważniana tylko dla wcześniej zapisanych danych. Dokument RFC (wydaje się) wyraźnie wyjaśnia, że tak, POST
żądania można buforować :
9.5 POST
..
Responses to this method are not cacheable, unless the response
includes appropriate Cache-Control or Expires header fields. However,
the 303 (See Other) response can be used to direct the user agent to
retrieve a cacheable resource.
Pomimo tego języka ustawienie Cache-Control
nie może buforować kolejnych POST
żądań do tego samego zasobu. POST
żądania należy wysyłać do serwera:
13.11 Write-Through Mandatory
..
All methods that might be expected to cause modifications to the
origin server's resources MUST be written through to the origin
server. This currently includes all methods except for GET and HEAD.
A cache MUST NOT reply to such a request from a client before having
transmitted the request to the inbound server, and having received a
corresponding response from the inbound server. This does not prevent
a proxy cache from sending a 100 (Continue) response before the
inbound server has sent its final reply.
W jaki sposób to ma sens? Cóż, nie buforujesz POST
żądania, buforujesz zasób.
Treść odpowiedzi POST może być buforowana tylko dla kolejnych żądań GET do tego samego zasobu. Ustaw nagłówek Location
lub Content-Location
w odpowiedzi POST, aby poinformować, który zasób reprezentuje treść. Zatem jedynym technicznie poprawnym sposobem buforowania żądania POST jest wykonanie kolejnych GET w tym samym zasobie.
Prawidłowa odpowiedź to:
Chociaż RFC zezwala na buforowanie żądań do tego samego zasobu, w praktyce przeglądarki i sieci CDN nie implementują tego zachowania i nie pozwalają na buforowanie żądań POST.
Źródła:
Biorąc pod uwagę następującą przykładową aplikację JavaScript (index.js):
const express = require('express')
const app = express()
let count = 0
app
.get('/asdf', (req, res) => {
count++
const msg = `count is ${count}`
console.log(msg)
res
.set('Access-Control-Allow-Origin', '*')
.set('Cache-Control', 'public, max-age=30')
.send(msg)
})
.post('/asdf', (req, res) => {
count++
const msg = `count is ${count}`
console.log(msg)
res
.set('Access-Control-Allow-Origin', '*')
.set('Cache-Control', 'public, max-age=30')
.set('Content-Location', 'http://localhost:3000/asdf')
.set('Location', 'http://localhost:3000/asdf')
.status(201)
.send(msg)
})
.set('etag', false)
.disable('x-powered-by')
.listen(3000, () => {
console.log('Example app listening on port 3000!')
})
Biorąc pod uwagę następującą przykładową stronę internetową (index.html):
<!DOCTYPE html>
<html>
<head>
<script>
async function getRequest() {
const response = await fetch('http://localhost:3000/asdf')
const text = await response.text()
alert(text)
}
async function postRequest(message) {
const response = await fetch(
'http://localhost:3000/asdf',
{
method: 'post',
body: { message },
}
)
const text = await response.text()
alert(text)
}
</script>
</head>
<body>
<button onclick="getRequest()">Trigger GET request</button>
<br />
<button onclick="postRequest('trigger1')">Trigger POST request (body 1)</button>
<br />
<button onclick="postRequest('trigger2')">Trigger POST request (body 2)</button>
</body>
</html>
Zainstaluj NodeJS, Express i uruchom aplikację JavaScript. Otwórz stronę internetową w przeglądarce. Wypróbuj kilka różnych scenariuszy, aby przetestować zachowanie przeglądarki:
Pokazuje to, że nawet jeśli można ustawić nagłówki Cache-Control
i Content-Location
odpowiedzi, nie ma sposobu, aby pamięć podręczna przeglądarki była żądaniem HTTP POST.
Zachowania przeglądarki nie można konfigurować, ale jeśli nie jesteś przeglądarką, niekoniecznie obowiązują Cię zasady RFC.
Jeśli piszesz kod aplikacji, nic nie stoi na przeszkodzie, aby jawnie buforować żądania POST (pseudokod):
if (cache.get('hello')) {
return cache.get('hello')
} else {
response = post(url = 'http://somewebsite/hello', request_body = 'world')
cache.put('hello', response.body)
return response.body
}
Sieci CDN, serwery proxy i bramy również nie muszą być zgodne ze specyfikacją RFC. Na przykład, jeśli używasz Fastly jako swojej sieci CDN, Fastly umożliwia pisanie niestandardowej logiki VCL w celu buforowania żądań POST .
To, czy żądanie POST powinno być buforowane, czy nie, zależy od kontekstu.
Na przykład możesz wysyłać zapytania do Elasticsearch lub GraphQL za pomocą POST, gdy Twoje zapytanie bazowe jest idempotentne. W takich przypadkach buforowanie odpowiedzi w pamięci podręcznej może mieć sens lub nie, w zależności od przypadku użycia.
W RESTful API żądania POST zwykle tworzą zasób i nie powinny być buforowane. Jest to również rozumienie przez RFC POST, że nie jest to operacja idempotentna.
Jeśli używasz GraphQL i potrzebujesz buforowania HTTP w sieciach CDN i przeglądarkach, zastanów się, czy wysyłanie zapytań za pomocą metody GET spełnia Twoje wymagania zamiast POST . Uwaga: różne przeglądarki i sieci CDN mogą mieć różne limity długości URI, ale lista bezpiecznych operacji (biała lista zapytań), jako najlepsza praktyka dla zewnętrznych aplikacji GraphQL, może skrócić identyfikatory URI.
Jeśli jest to coś, co w rzeczywistości nie zmienia danych w Twojej witrynie, powinno to być żądanie GET. Nawet jeśli jest to formularz, nadal możesz ustawić go jako żądanie pobierania. Chociaż, jak wskazują inni, można buforować wyniki testu POST, nie miałoby to sensu semantycznego, ponieważ z definicji POST zmienia dane.
W przypadku przeglądarki Firefox 27.0 i httpfox 19 maja 2014 r. Zobaczyłem jedną linię: 00: 03: 58.777 0,488 657 (393) POST (Cache) text / html https://users.jackiszhp.info/S4UP
Oczywiście odpowiedź metody post jest przechowywana w pamięci podręcznej, a także w https. Nie do wiary!
POST jest używany w stanowym Ajaxie. Zwracanie buforowanej odpowiedzi na POST niweczy kanał komunikacyjny i skutki uboczne otrzymania wiadomości. To jest bardzo, bardzo złe. To także prawdziwy ból do wytropienia. Gorąco polecam przeciwko.
Trywialnym przykładem może być wiadomość, że efektem ubocznym jest wypłata pensji w wysokości 10 000 USD w bieżącym tygodniu. NIE chcesz, aby komunikat „OK, przeszedł!” strona wstecz, która została zapisana w pamięci podręcznej w zeszłym tygodniu. Inne, bardziej złożone przypadki w świecie rzeczywistym skutkują podobną wesołością.