Cache, ETag, Expires a pravděpodobná chyba v Nette
- Tomáš Jacík
- Člen | 147
Rozhodl jsem se načítat strom kategorií AJAXem, cachovat jej a neodesílat jej zbytečně když se nezměnil. Vypadá to takto:
/** @var Nette\Http\Context @inject */
public $httpContext;
/** @var Nette\Caching\IStorage @inject */
public $cacheStorage;
public function renderMenu()
{
$cache = new Cache($this->cacheStorage, 'App');
$categoryTree = $cache->load('ajaxCategoryTree');
if (!$categoryTree)
{
$categoryTree = $this->getCategoryTree();
$cache->save('ajaxCategoryTree', $categoryTree, array(
Cache::EXPIRE => '5 minutes'
));
}
$etag = md5(serialize($categoryTree));
if ($this->httpContext->isModified(NULL, $etag))
{
$this->payload->categories = $categoryTree;
$this->sendPayload();
}
$this->getHttpResponse()->setContentType('application/json', 'UTF-8');
$this->getHttpResponse()->setExpiration('+5 minutes');
$this->terminate();
}
Takto mi to funguje skvěle, ale nezdá se mi jak to v Nette funguje.
- Response si získám pohodově z presenteru, ale Http\Context musím injectovat a to jen kvůli jedné metodě, kterou potřebuju použít. Nemělo by to být spíše někde pohromadě s metodou setExpiration?
- Když pouiju isModified, nenastaví se mi expiration a tím pádem je ten zasílaný ETag stejně v response zbytečný, tak to musím takto použít z obou míst.
- Když nenastavím natvrdo Content-Type na json, tak to v případě 304 posílá debug, to je imho chyba, response by měla být prázdná.
- Bylo by fajn mít v Nette na celou tuhle proceduru nějaký helper a nerozepisovat to takto.
- Milo
- Nette Core | 1283
Tomáš Jacík napsal(a):
Takto mi to funguje skvěle, ale nezdá se mi jak to v Nette funguje.
- Response si získám pohodově z presenteru, ale Http\Context musím injectovat a to jen kvůli jedné metodě, kterou potřebuju použít. Nemělo by to být spíše někde pohromadě s metodou setExpiration?
HTTP hlavičky ETag
a Expire
jsou dvě různé
techniky kešování. Mají fungovat odděleně. Pro ETag
validaci
potřebuješ od browseru If-None-Match
hlavičku. Tj. potřebuješ
Request i Response, v Nette zabalené v Http\Context. U ETag
techniky se request dostane vždy až do tvojí aplikace. Šetří se jen objem
přenesených dat, serveru se neodlehčí.
U Expire
poznačíš, jak dlouho response platí. Tj. browser se
dalších X minut ani nemusí zeptat anebo odpoví cestou proxy a na server se
request ani nedostane.
- Když pouiju isModified, nenastaví se mi expiration a tím pádem je ten zasílaný ETag stejně v response zbytečný, tak to musím takto použít z obou míst.
viz.1 Btw. Http\Context
má metodu
getResponse()
- Když nenastavím natvrdo Content-Type na json, tak to v případě 304 posílá debug, to je imho chyba, response by měla být prázdná.
Tracy to tak detekuje. Defaultní je totiž text/html
a Tracy
tak může přidat kus HTML. Ale nevím, jestli to považovat za bug,
možná jo.
- Tomáš Jacík
- Člen | 147
Ahoj, díky za reakci. Vím že ETag a expire jsou dvě různé věci. Snažil jsem se poznamenat, že bez nastavení expire je to nastavení ETagu stejně k ničemu, expire je totiž defaultně v minulosti a tak se browser příště ptá bez etagu (304 se zobrazí jen jednou a vyruší ho ten expire).
Také vím že Context má Request a Response, ale ten kontext potřebuji kvůli nastavení ETagu, versus Response potřebuju kvůli nastavení Expire, což by po nastavení ETagu nemělo být nutné. Navíc se každá z těch věcí získává jinou metodou, což považuji za nekonzistentní.
Víceméně, pro mě už to funguje jak potřebuju. Hledám způsob, jak to udělat jednodušeji, nebo někoho postrčit, aby to v budoucnu jednodušší bylo.