Flash zprávičky bez _fid v URL

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Ondřej Mirtes
Člen | 1536
+
+1
-

Ahoj,
došli jsme v práci k závěru, že přidávání _fid parametru do URL je ošklivá vlastnost Nette a způsobuje to problémy – generuje to duplicity pro vyhledávače a znepřehledňuje statistiky. Udělali jsme tedy nový namespace a do něj bez jakéhokoli idenfitikátoru ukládáme rovnou ty flash zprávičky.

Překrývající metody v BasePresenteru:

public function hasFlashSession()
{
	return $this->getSession()
		->hasNamespace('Medio.Application.Flash');
}

public function getFlashSession()
{
	return $this->getSession('Medio.Application.Flash');
}

A namísto nastavování nějaké expirace (jak to probíhá v Presenter::run()) promazáváme session objekt těsně po vytvoření a naplnění šablony (kdy si jsme de facto jisti, že dojde k vykreslení stránky, potažmo flash zprávičky):

protected function createTemplate()
{
	$template = parent::createTemplate();

	// renderer flash messages deleting
	if ($this->hasFlashSession()) {
		unset($this->getFlashSession()->{$this->getParamId('flash')});
	}

	return $template;
}

Neušili jsme si tím na sebe nějakou boudu? Proč to takhle nefunguje v Nette?

Jediné dva případy, co mě napadají, kdy může nastat nějaký zádrhel:

  • Programátor nenásleduje best practices a plní šablonu v action* metodě: Při prvním volání $this->template->cokoli se zavolá createTemplate(), jenže po action* metodě může nastat nějaký redirect v handle fázi. V tu chvíli se flash zprávička ztratí a nikdy se nezobrazí.
    • Z našeho hlediska to nepovažuji za problém, protože programátory, kteří plní šablonu v action*, mlátíme přes prsty :))
  • Uživatel nějakým způsobem dokáže zobrazit dva requesty v ± stejnou chvíli a tehdy se může stát, že se mu zobrazí flash zprávička v jiném, nesouvisejícím tabu prohlížeče.
    • Nenapadá mě, kdy by to mohlo v praxi nastat, maximálně na nějakém pomalém připojení.

Brání něco tomu, aby se tento fix dostal do Nette, zamezuje předávání _fid v URL nějakým dalším problémům, které si neuvědomujeme? Díky.

redhead
Člen | 1313
+
0
-

Podle mě tím důvodem byl bod 2).

A podle mě to takhle kdysi dávno i bylo, ale právě kvůli tomu bodu 2 se to přenáší v URL. Navíc se mi nezdá, že to by to mělo mást vyhledávače. Já teda dávám flashmessages po nějaké velké akci, jako smazání příspěvku nebo odeslání formuláře. A v tom si myslím, že problém pro vyhledávače není, nebo jo?

Ale víc ti řekne někdo zkušenější..

Ondřej Mirtes
Člen | 1536
+
0
-

Sice dáváš flash message po akci, co mění server, ale tu URL s _fid můžeš třeba nevědomky použít jako nějaký zpětný odkaz a může se začít šířit – a duplicita je na světě.

Honza Marek
Člen | 1664
+
0
-

Ondřej Mirtes napsal(a):

Ahoj,
došli jsme v práci k závěru, že přidávání _fid parametru do URL je ošklivá vlastnost Nette a způsobuje to problémy – generuje to duplicity pro vyhledávače a znepřehledňuje statistiky.

Tady souhlas.

Programátor nenásleduje best practices a plní šablonu v action* metodě: Při prvním volání $this->template->cokoli se zavolá createTemplate(), jenže po action* metodě může nastat nějaký redirect v handle fázi. V tu chvíli se flash zprávička ztratí a nikdy se nezobrazí.

IMHO to problém je a represe v podobě rozmlácených programátorských rukou tomu nepomůže :) Přece když vydoluju něco z modelu a chci to použít jak na rozhodnutí o přesměrování, tak v šabloně, tak to nebudu sosat zbytečně ve dvou metodách.

Jan Tvrdík
Nette guru | 2595
+
0
-

Doplním: Starší, ale předpokládám stále platné vysvětlení od Davida.

Jak vznikají ty duplicity pro vyhledávače? Používám to akorát po odeslání formuláře a roboti, pokud vím, formuláře neodesílají. Dobrý analytický systém by měl umět vybrané parametry ignorovat.

Honza Kuchař
Člen | 1662
+
0
-

Podle mě:

  • Nechat _fid v url z výše uvedeného důvodu.
  • Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid. Tím se vyřeší problém s vyhledávači.
Majkl578
Moderator | 1364
+
0
-

Honza Kuchař napsal(a):

  • Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid. Tím se vyřeší problém s vyhledávači.

Tohle zní dost rozumně. Jsem pro.

Yrwein
Člen | 45
+
0
-

Honza Kuchař napsal(a):

  • Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid. Tím se vyřeší problém s vyhledávači.

→ Nevznikne tak problém při akci s GET?

Honza Kuchař
Člen | 1662
+
0
-

Yrwein napsal(a):

Honza Kuchař napsal(a):

  • Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid. Tím se vyřeší problém s vyhledávači.

→ Nevznikne tak problém při akci s GET?

Proč myslíš? Nějak nevidím, kde by mohl být problém. Píšu tam, pokud už to v session není, tzn. po uplynutí těch tří sekund. Tzn. i pokud se to _fid dostane do nějakého odkazu, budeš třistajedničkou přesměrován na adresu bez _fid → je prakticky nulová možnost, že by se to zaindexovalo, musel by se tam dostat robot do těch tří sekund od odeslání flash zprávičky.

kravčo
Člen | 721
+
0
-

Honza Kuchař napsal(a):

Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid.

Neviem ako vy, ale ja tento postup používam už dlhšie…

PetrP
Člen | 587
+
0
-

Odstraněním fid z url není dobře.

Víče requestů najednou může vznikat poměrně často.

V createTemplate odstraníte zprávy z session takže když omylem během vykreslovaní refreshnu tak message ztratím.

Lepší je řešit zkutečnej problém a to jsou duplicity. Takže jak tady píšou jiný kdyz fid v session neexistuje tak kanonizovat url. Podle mě by se o to měl postarat už framework.

Honza Marek
Člen | 1664
+
0
-

Přiznejte se, kdo odesíláte ve dvou tabech dva formuláře naráz? Já jsem to teda ještě nikdy neudělal. Naprosto nechápu proč bych to měl, natožpak často.

I když je pravda, že _fid si v adrese těžko vyrobí sám vyhledávač, snadno se taková adresa může zveřejnit, pokud ji někam zkopíruje sám uživatel.

mlady
Člen | 24
+
0
-

Honza Marek napsal(a):

Přiznejte se, kdo odesíláte ve dvou tabech dva formuláře naráz? Já jsem to teda ještě nikdy neudělal. Naprosto nechápu proč bych to měl, natožpak často.

Napríklad v administrácií domén active24 som si v taboch otvoril niekoľko formulárov na pridanie záznamov a potom som ich postupne posielal. Ak by mi to nefungovalo, dosť by mi to vadilo.

Ondřej Brejla
Člen | 746
+
0
-

Ať tak, či tak, nejlepší by asi bylo, pokud by šlo stávající (bezpečné) chování vypnout a tím zapnout chování „nebezpečné“, tedy bez _fid v url. Jako s escapováním v šabloně…default bezpečné a escapované, po vypnutí „nebezpečné“ a neescapované ;-)

Honza Marek
Člen | 1664
+
0
-

mlady napsal(a):

Napríklad v administrácií domén active24 som si v taboch otvoril niekoľko formulárov na pridanie záznamov a potom som ich postupne posielal. Ak by mi to nefungovalo, dosť by mi to vadilo.

Vidíš, dělal jsi to postupně. Čili ne najednou :)

Honza Kuchař
Člen | 1662
+
0
-

Pořád mi přidadá jako nejlepší řešení to přesměrování, co jsem psal výše.

Ondřej Mirtes
Člen | 1536
+
0
-

Že se zobrazí flash zprávička v jiném tabu, než může, je pořád hodně nepravděpodobné. Návštěvník by se musel strefit načítáním webu ve druhém tabu do momentu, který tady zkusím rozepsat (na posloupnosti zpracování prvního tabu):

  • Vyplňuji formulář
  • Klikám na submit
  • Formulář se odesílá (upload hodnot a souborů na server)
  • Formulář se zpracovává na serveru, ukládá do databáze, provádí se cokoli, co je třeba
  • Až do tohoto momentu se v ostatních tabech webu nemůže zobrazit žádná flash zprávička.
  • Nastavení flash zprávičky
  • Nyní je ta riziková část, kdy je v session nastavená flash zprávička a tudíž se může vykreslit na kterémkoli tabu webu.
  • Redirect.
  • Čekání na odezvu serveru.
  • Na serveru se spouští Presenter a za chvíli se volá createTemplate, který flash zprávičku odstraní.
  • Končí riziková část, nyní se flash zprávička zobrazí, pokud ji neukradl jiný tab.

Takže jde o to, trefit se do toho redirectu a čekání na odezvu serveru. A neumím si představit, že bych se do toho trefil, leda, že by server měl na tu odezvu na redirect velký timeout anebo bych byl na pomalém připojení. Ale zase když jsem na pomalém připojení, tak ty další otevřený taby se vykreslí ještě později, než ten první po redirectu.

Honza Kuchař
Člen | 1662
+
0
-

Ale podle mě je uživatelovi úplně jedno co je v url. //EDIT: Jde o vyhledávače.

Editoval Honza Kuchař (21. 5. 2010 15:41)

Honza Kuchař
Člen | 1662
+
0
-

PetrP napsal(a):

Odstraněním fid z url není dobře.

Víče requestů najednou může vznikat poměrně často.

V createTemplate odstraníte zprávy z session takže když omylem během vykreslovaní refreshnu tak message ztratím.

Lepší je řešit zkutečnej problém a to jsou duplicity. Takže jak tady píšou jiný kdyz fid v session neexistuje tak kanonizovat url. Podle mě by se o to měl postarat už framework.

100% souhlasím.

veena
Člen | 98
+
0
-

Ondřej Mirtes napsal(a):

Že se zobrazí flash zprávička v jiném tabu, než může, je pořád hodně nepravděpodobné. Návštěvník by se musel strefit načítáním webu ve druhém tabu do momentu, který tady zkusím rozepsat (na posloupnosti zpracování prvního tabu):

  • Vyplňuji formulář
  • Klikám na submit
  • Formulář se odesílá (upload hodnot a souborů na server)
  • Formulář se zpracovává na serveru, ukládá do databáze, provádí se cokoli, co je třeba
  • Až do tohoto momentu se v ostatních tabech webu nemůže zobrazit žádná flash zprávička.
  • Nastavení flash zprávičky
  • Nyní je ta riziková část, kdy je v session nastavená flash zprávička a tudíž se může vykreslit na kterémkoli tabu webu.
  • Redirect.
  • Čekání na odezvu serveru.
  • Na serveru se spouští Presenter a za chvíli se volá createTemplate, který flash zprávičku odstraní.
  • Končí riziková část, nyní se flash zprávička zobrazí, pokud ji neukradl jiný tab.

Takže jde o to, trefit se do toho redirectu a čekání na odezvu serveru. A neumím si představit, že bych se do toho trefil, leda, že by server měl na tu odezvu na redirect velký timeout anebo bych byl na pomalém připojení. Ale zase když jsem na pomalém připojení, tak ty další otevřený taby se vykreslí ještě později, než ten první po redirectu.

Mě se to stávalo pravidelně. Ne sice na Nette ale v administraci Django. Server v Americe, ping cca 170ms.

nAS
Člen | 277
+
0
-

Mě se to stávalo v Drupalu, když se nepodařilo načíst stránku na kterou se redirectilo, tak SESSION zůstala platná a zobrazila se v úplně nesouvisejícím okně.

mlady
Člen | 24
+
0
-

Honza Marek napsal(a):

Vidíš, dělal jsi to postupně. Čili ne najednou :)

Ako sa to vezme. Pri pomalšom pripojení by to mohlo byť „naraz“. V práci s tým občas problémy máme. Okrem toho „flash zprávičky“ sa môžu využívať aj mimo formulárov. Alebo nie? Súhlasím s príspevkami vyššie, že je potrebné vyriešiť duplicitu a nie formát URL.

David Grudl
Nette Core | 8227
+
-1
-

_fid v žádném případě rušit nebudu, být teď v Simpsonových, pustili by instruktážní video s Troy McClurem (možná si ho pamatujete ze snímků jako Malomocný za čárou, Dnes zabij a zítra zemři, Mami co to ten pán má s obličejem, nebo Maso a My).

Přesměrování při neexistujícím _fid: měl jsem za to, že to tam dávno je :-) Podívám se.

David Grudl
Nette Core | 8227
+
0
-

Honza Kuchař napsal(a):

Podle mě:

  • Pokud _fid nebude při dotazu nalezeno v session a zároveň to nebude POST požadavek, tak bych to přesměroval na adresu bez _fid. Tím se vyřeší problém s vyhledávači.

Po přesměrování to zcela jistě nebude POST požadavek.

Honza Kuchař
Člen | 1662
+
0
-

Pokud to bude POST, tak nepřesměrovávat! Přesměrovávat pouze, pokud je to GET a už _fid není v SESSION. Tzn. vyhledáváč se dostanen na kanonikalizovanou url.

EDIT:

Přesměrování při neexistujícím _fid: měl jsem za to, že to tam dávno je :-) Podívám se.

Opravdu je to tak: https://componette.org/search/?…

Editoval Honza Kuchař (21. 5. 2010 21:09)

Honza Kuchař
Člen | 1662
+
0
-

Přemýšlím, jak udělat tu identifikaci okna nějak obecně. Taková vlastnost by byla naprosto klíčová při tvorbě live-aplikací. Ale nenapadá mě žádné obecné řešení, aby to bylo zároveň bez duplicitních stránek. //EDIT: Facebook to musí určitě taky nějak řešit.

Editoval Honza Kuchař (21. 5. 2010 21:10)

ic
Člen | 430
+
0
-

Možná by bylo dobře při adrese s ?fid=XXX přidat taky rel="canonical" s odkazem na verzi bez _fid aby vyhledávač (alespoň google, nevím jak jsou na tom ostatní) věděl o kterou stránku se má zajímat… teoreticky by tohle mohly pochopit i prohlížeče… že web.cz/stranka/?fid=XXX je to samé jako web.cz/stranka/ a zobrazit ji jako už navštívenou, pokud by na první adrese našly canonical směřující právě na tu druhou, ale to už je v kompetencích někoho jiného.

Honza Kuchař
Člen | 1662
+
0
-

Myslím, že je to téměř zbytečné. Redirect bude fungovat na 100%.

JakubJarabica
Gold Partner | 184
+
0
-

K čomu sa teda dospelo? Bude Nette natívne podporovať 301 na kanonickú verziu v prípade, že flash session bude prázdna? Najviac sa mi ľúbi riešenie v tomto poste: p32806, avšak neviem si predstaviť, kde už v tej fázi začať plniť šablónu nejakou kanonickou URL v prípade výpisu flashMessage a taktiež kde presmerovávať v prípade prázdnej session.

Majkl578
Moderator | 1364
+
0
-

Já prozatím řeším kanonizaci při neexistující zprávičce takto:

//Presenter::startup()
if (!$this->hasFlashSession() && !empty($this->params[self::FLASH_KEY])) {
	unset($this->params[self::FLASH_KEY]);
	$this->redirect('this');
}
JakubJarabica
Gold Partner | 184
+
0
-

Vďaka, narval som to do startupu BasePresenteru a funguje to. Ešte nejako efektívne vymyslieť link rel=„canonical“ a bude to dokonalé :)

Edit:
Tak ešte som pridal do redirectu ako prvý parameter 301tku, pre prípad, keď nejaký používateľ skopíruje link s _fid a prilinkuje.

Editoval JAM3SoN (5. 6. 2010 15:52)

Ola
Člen | 385
+
0
-

Ten rel canonical by měl jít nějak takhle:

<link rel="canonical" href="{link this, Presenter::FLASH_KEY => NULL}" />

příp. v 5.3:

<link rel="canonical" href="{link this, \Nette\Application\Presenter::FLASH_KEY => NULL}" />

Editoval Ola (5. 6. 2010 18:23)

Majkl578
Moderator | 1364
+
0
-

Ten kód od Ola bych ještě podmínil na existenci (k čemu odkaz na kanonickou url na kanonické url?):

<link rel="canonical" href="{link this, Nette\Application\Presenter::FLASH_KEY => NULL}" n:if="$presenter->getParam(Nette\Application\Presenter::FLASH_KEY)" />
Ola
Člen | 385
+
0
-

K ničemu, ale ani to ničemu (snad) neuškodí :-)

Majkl578
Moderator | 1364
+
0
-

Pushl jsem tu automatickou kanonizaci na github (upraveno 30.6. na základě doporučení Honzy Tvrdíka) a poslal pull request.

Editoval Majkl578 (30. 6. 2010 3:41)

ic
Člen | 430
+
0
-

Majkl578 napsal(a):

Pushl jsem tu automatickou kanonizaci na github a poslal pull request.

doufám že to dopadne XD

ic
Člen | 430
+
+2
-

V návaznosti na tento tweet http://twitter.com/…425037574145 a hlavně na jeho odpovědi mě napadlo že by možná šlo ty ?_fid=XXXX skrýt odebráním z URI adresy javascriptem. A vono jo!

tohle

if(window.history.replaceState){l=window.location.toString();u=l.indexOf('_fid=');if(u!=-1){u=l.substr(0,u)+l.substr(u+10);if(u.substr(u.length-1)=='?'||u.substr(u.length-1)=='&')u=u.substr(0,u.length-1);window.history.replaceState('',document.title,u)}}

nebo čitelněji tohle:

if(window.history.replaceState) {
	l = window.location.toString();
	uri = l.indexOf('_fid=');
	if(uri != -1) {
		uri = l.substr(0, uri)+l.substr(uri+10);
		if( (uri.substr(uri.length-1) == '?') || (uri.substr(uri.length-1) == '&') ) {
			uri = uri.substr(0, uri.length-1);
		}
		window.history.replaceState('', document.title, uri);
	}
}

k tomu dopomůže… podle working draft html5 ( http://dev.w3.org/…history.html#… ) by to v budoucnu mělo fungovat. Zatím to funguje pouze na Chrome 7 , jinde to sice nedělá nic, ale snad neuškodí.

EDIT: Skutečná adresa tam na několik málo ms problikne, záleží podle toho jak rychle se script vykoná, takže je nejlepší ho umístit na začátek head. V kombinaci s řešeními z předchozích příspěvků se dá taky tento javascript vkládat jen do stránek s aktivní flash zprávičkou.

Editoval ic (10. 11. 2010 20:42)

romiix.org
Člen | 343
+
0
-

Nemalo by toto riešiť samotné Nette?

Majkl578 napsal(a):

Já prozatím řeším kanonizaci při neexistující zprávičce takto:

//Presenter::startup()
if (!$this->hasFlashSession() && !empty($this->params[self::FLASH_KEY])) {
	unset($this->params[self::FLASH_KEY]);
	$this->redirect('this');
}
mcmatak
Člen | 504
+
0
-

Mohl by mi někdo vysvětlit ty duplicity?

Resp.

  1. různá url (včetně _fid), stejný obsah = špatně,
  2. stejná url, různý obsah = super cool,

tak to bychom měli, to víme.

Kde jsou ty duplicity? Resp. jak se vyhledávač dostane na _fid? Vy třeba kliknutím na detail článku z výpisu článku oznamujete uživateli pomocí flashmsg že se dostal na detail článku?

Určitě znáte Czechcomputer tam, když se stane nějaká akce tak jste o tom informování textem na bílém pozadí uprostřed obrazovky, což je alternativa k flashmsg, nebylo by rozumnější vyhledávači zakázat indexovat tuto stránku?

Majkl578
Moderator | 1364
+
0
-

mcmatak napsal(a):

Kde jsou ty duplicity? Resp. jak se vyhledávač dostane na _fid?

  1. Uživatel A napíše do diskuze, příspěvek se přidá a uživatel je přesměrován na výpis diskuze (s flash zprávičkou o přidání).
  2. Uživatel A veme odkaz z adresového řádku prohlížeče a postne ho někam jinam, třeba na blog.
  3. Uživatel B udělá totéž co uživatel A.
  4. Uživatel C udělá totéž co uživatelé A a B.

Voila! Máme tu 3 duplicity. A zrovna tenhle příklad mi nepřijde nereálný.

kravčo
Člen | 721
+
0
-

Možno by stačilo použiť <link rel="canonical" href="http://canonical.url/with/path?and=query" />?

David Grudl
Nette Core | 8227
+
0
-

romiix.org napsal(a):

Nemalo by toto riešiť samotné Nette?

Je to v plánu

mcmatak
Člen | 504
+
0
-

ok Majkl to máš recht, nějak jsem to opomněl, každopádně v takovém případě podle mne žádné flashmsg neexistují pro toho nevě otevíraného, tedy google, a tím pádem můžu s klidem přesměrovat na bez fid protože google žádnou session nevytvořil a voila máme řešení ne?

Dr.Diesel
Člen | 53
+
0
-

Nette pokud vim v pripade pouziti fid parametru nema jednorazovou povahu, ale ma to expiraci na par sekund (1 nebo vic, ted z hlavy nevim). Prave kvuli ruznym presmerovani nebo (nepravdepodobne) refreshi uzivatele kratce po zobrazeni stranky (1s?)

Ondrovo reseni toto ztrati a zobrazeni ma jednorazovou povahu, jestli se nemylim.

Editoval Dr.Diesel (8. 12. 2010 10:50)

Felix
Nette Core | 1245
+
0
-

Muzu se zeptat, jakto ze sem nevidel na ofic. strankach nette nikde zadny fid v url? :) Neni to nic hroznyho, resim to spise z estetickeho hlediska..

Editoval Felix (22. 1. 2011 22:05)

Honza Marek
Člen | 1664
+
0
-

Asi protože jsi ještě needitoval žádnou stránku v dokumentaci.

ic
Člen | 430
+
0
-

@Felix teď už najdeš _fid=… i na new.csfd.cz, ale taky až po provedení nějaké editace

Felix
Nette Core | 1245
+
0
-

ic napsal(a):

@Felix teď už najdeš _fid=… i na new.csfd.cz, ale taky až po provedení nějaké editace

Tak to to ;-) Nejak extreme mne to nevadi, hledal jsem jen neco co by to mohlo skryt. Stara verze csfd nebezi na nette?

Lopata
Člen | 139
+
0
-

Ne.

JakubJarabica
Gold Partner | 184
+
0
-

Tak práve som to akútnejšie riešil v jednom projekte a skončil som s týmto:
BasePresenter.php

<?php
// kód myslím, že od Majkla, ktorý po refreshi odstráni _fid z URL
if (!$this->hasFlashSession() && !empty($this->params[self::FLASH_KEY])) {
	unset($this->params[self::FLASH_KEY]);
	$this->redirect(301, 'this');
}
?>

FrontModule\BasePresenter.php

<?php
    public function beforeRender() {
        parent::beforeRender();
        $fid = $this->getParam(self::FLASH_KEY);
        if ($fid !== NULL) { // ak máme FID, vygeneruj kanonický odkaz na samého seba
            $this->template->canonical = $this->link('//this');
        }
    }
?>

.. a príslušný @layout.latte

<?php
	<link rel="canonical" n:ifset="$canonical" href="{$canonical}" />
?>

Napadá niekoho elegantnejšie a lepšie riešenie z pohľadu SEO?