Devel.cz Lupa Měšec Podnikatel Root Zdroják.cz DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Názory k článku
Post-Redirect-Get (nejen) v ASP.NET MVC

architekt_ aura:93
10. 8. 2009 10:13 Nový

Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Pěkný článek, jen si myslím, že Post-Redirect-Get je obecně rozšířený omyl, který dává pocit bezpečnosti, ale prakticky nic moc neřeší.

Hlavním jeho nedostatkem je, že neřeší situaci, kdy uživatel použije v prohlížeči zpět a formulář odešle znovu (což je častější případ než že zmáčkne F5). Takže je to jen polovičaté řešení, které vůbec nemusí řešit to, co si klade za cíl. Proto se taky skoro nepoužívá (tedy ne z důvodu ochrany proti opakovanému odeslání dat, jak je prezentováno v článku).

Tento problém se řeší až na straně aplikace. A to tak, že každý formulář obsahuje jedinečný klíč (jak je dnes dobrým zvykem i v rámci ochrany proti CSRF), podle kterého aplikace pozná, jestli se jedná o opakovaně odeslaný formulář.

developer_
developer_ (neregistrovaný) ---.infonet.cz
10. 8. 2009 11:03 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Používáme Post-Redirect-Get ve všech aplikacích tak asi 10 let a nemáme jediný problém s duplicitou odeslaných dat. Neznám ani framework s podporou jedinečných klíčů. To je pro změnu můj názor za léta programování pro web.

Michal Augustýn
10. 8. 2009 12:17 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Díky za reakci a doplnění. Použití tlačítka Zpět je opravdu jedním z dalších problémů, který PRG řeší (a IMHO ho opravdu řeší).

Upřímně řečeno mě ani nenapadl problém s tlačítkem zpět (tedy to, že by ho PRG neřešil). Když server vrátí jako reakci na POST jen hlavičku s redirektem (nějakou třístovku), tak prohlížeč tuto POSTovanou adresu do historie neuloží (teď testováno na IE8, Firefox 3 a Chrome 2) – však by ani nevěděl, jaký title jí přiřadit.

Samozřejmě jistě existují prohlížeče či konfigurace prohlížečů, které nám do historie uloží i POSTované stránky, ale IMHO jsou v drtivé menšině.

Ladislav Thon
Ladislav Thon (neregistrovaný) ---.net.upc.cz
10. 8. 2009 12:27 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

IMHO pán architekt měl na mysli situaci, kdy se uživatel po regulérním odeslání formuláře vrátí na předchozí stránku s formulářem a znovu klikne na „Odeslat“. To opravdu redirect after POST nevyřeší.

Což pravda nic nemění na tom, že redirect after POST je naprosto základní technika, která by se měla aplikovat vždy a všude :-)

architekt_ aura:93
10. 8. 2009 12:39 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Jde o to, že po tom použití tlačítka zpět uživatel znovu odešle formulář. Typicky stránka (skript) která formulář zpracuje je v pořádku (všechny data se zpracovaly v pořádku) a až na té přesměrované se něco „pokazí“ (nenačte se správně, internal server error, atp.). Když dá uživatel F5, nic se nestane, protože to řeší PRG. Ale spousta (většina) uživatelů F5 nezná/nepoužívá, dají místo toho zpět a pošlou formulář znovu.

Mimochodem s tím jedinečným klíčem ve formuláři se dá pořešit i situace, kdy dojde k neočekávané chybě už během zpracovávání dat z formuláře. Né vždy může celé zpracování probíhat jako transakce, která když se nedokončí, tak se nic nestane. Po opětovném odeslání formuláře uživatelem může aplikace ověřit/dokončit předchozí pokus o zpracování dat.

Michal Augustýn
10. 8. 2009 12:25 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Aha, přečetl jsem si Vaši reakci ještě jednou a už asi chápu, co jste myslel – návrat na původní GETnutou stránku (často vytaženou z cache) a její další odeslání. Pak je jistě dobrou ochranou použití CSRF tokenu. V ASP.NET MVC to lze velmi jednoduše – při renderování View stačí zavolat Html.AntiForge­ryToken() a POSTovací akci odekorovat atributem ValidateAntiFor­geryToken.

xurfa
xurfa (neregistrovaný) ---.adsl.sky.cz
12. 8. 2009 15:05 Nový

Re: Post-Redirect-Get je kontroverzní návrhový vzor

celé vlákno

Jasně, ale je tu jeden zásadní rozdíl: při Post-Redirect-Get je jediná možnost, jak může uživatel formulář odeslat ta, že vyvolá explicitní odeslání formuláře (tj. např. siskne tlačítko ve formuláří, nebo odentruje pole ve formuláři). Nikdy se to nestane mimoděk (např. tlačítkem zpět, apod.).

Honza77
Honza77 (neregistrovaný) ---.38.broadband13.iol.cz
11. 8. 2009 4:23 Nový

Opakované odeslání klávesou F5 to neřeší

celé vlákno

Opakované odeslání klávesou F5 to neřeší, pokud F5 stiskneme ještě v době, kde se zpracovává první stránka (tedy ta, která zpracovává přijmutá data a následně odesílá redirect).

Ale jinak samozřejmě je základní technika, i když ji nelze použít pro zabránění odeslání formuláře vícekrát.

Michal Augustýn
11. 8. 2009 9:38 Nový

Re: Opakované odeslání klávesou F5 to neřeší

celé vlákno

Dle mého názoru řeší (teď otestováno na IE8, Firefox 3 a Chrome 2). Browsery totiž po stisku F5, CTRL + F5 i refreshovacího tlačítka začnou znovu načítat poslední stránku z historie, kamžto se POSTovací request vůbec nedostane.

Borek Bernard aura:66
12. 8. 2009 14:30 Nový

Návrhový vzor

celé vlákno

Dík za moc pěkný článek, jen bych PRG rozhodně nenazval návrhovým vzorem.

51><
51>< (neregistrovaný) ---.smoula.net
12. 8. 2009 14:41 Nový

informace uzivateli o uspesnosti / neuspesnosti

celé vlákno

Zdravim,

PRG je nahodou celkem pekne reseni (asi otazka nazoru). Rad bych ale nadhodil k diskuzi, jak resit vetsnou uzivatelu ocekavanou zpravu o uspesnosti / neuspesnosti pozadavku.

situace rekneme pridani uzivatele v nejakem foru: GET /user/add
- uzivatel vyplni formular POST /user/add
- server zpracuje pozadavek a uzivatele do DB prida, posle 303 na /user/list GET /user/list
- uzivatel vidi seznam jiz existujicich uzivatelu

ovsem u tohoto seznamu urcite nechce hledat sveho uzivatele, zda byl pridan nebo ne. Tedy rad by videl krasnou zdlenou hlasku „uzivatel uspesne pridan“

jedno reseni, ktere me napada je poslat si zpravu jako get parametr, napriklad /user/list?msg=us­pesne%20pridan

toto reseni ma ale tu nevyhodu, ze ted kdyz uzivatel provede reload, uvidi zpravu znovu a zdesi se, ze uzivatel byl pridan znovu. Jine reseni me napada pridat si treba hlavicku do HTTP, kterou pak parsuji napr. javascriptem a na zaklade ni uzivateli zobrazim zpravu. Ale to mi zase neprijde moc koser vuci HTTP

jak toto resite vy?

Michal Augustýn
12. 8. 2009 17:11 Nový

Re: informace uzivateli o uspesnosti / neuspesnosti

celé vlákno
V ASP.NET MVC to řeším přes TempData. Pokud nepracujete v ASP.NET MVC, funguje to takto:
  • 1) Kdykoliv během zpracování požadavku na POST /user/add se uloží do session informace o úspěšnosti přidání.
  • 2) Provede se přesměrování na GET /user/list
  • 3) Při zpracování požadavku na GET /user/list se kouknu do session, jestli tam není nějaká zpráva k zobrazení.
  • 4) Na konci zpracování požadavku vymažu data se session.

Možná to vypadá složitě, ale princip fungování TempData je prostý:
  • 1) Na začátku požadavku se načtou do kolekce TempData všechny položky ze session (resp. načtou se z nějaké položky session, která je kolekcí).
  • 2) Na konci požadavku se do session uloží jen ty hodnoty z TempData, které byly přidány nebo upraveny.

Předání dat při přesměrování pak vypadá tak, že před přesměrováním data do TempData uložím a ve zpracování požadavku na GET /user/list se prostě kouknu do TempData, jestli tam něco není.
Btw. v ASP.NET MVC může být TempData implementováno více způsoby – defaultně je to pomocí session, ale existuje i varianta s cookies.
51><
51>< (neregistrovaný) ---.smoula.net
12. 8. 2009 17:28 Nový

Re: informace uzivateli o uspesnosti / neuspesnosti

celé vlákno

Vida, do session si ukladat veci, o kterych pri nejblizsi prilezitosti informovat … proc me to nenapadlo driv :)

Dobry napad, dik

Viktor
Viktor (neregistrovaný) ---.234.broadband3.iol.cz
12. 8. 2009 20:43 Nový

Re: informace uzivateli o uspesnosti / neuspesnosti

celé vlákno

A jak řešíte situace kdy není jednoznačné kam chce dále uživatel pokračovat, například nechce zobrazit seznam, ale přímo záznam vytvořeného uživatele, nebo chce ten seznam, nebo dokonce zůstat na stránce a přidat dalšího uživatele, atd…? Na straně serveru při zpracování post vyberete ten správný redirect, pokud ano, dává Vám to smysl? ;)

Michal Augustýn
12. 8. 2009 21:51 Nový

Re: informace uzivateli o uspesnosti / neuspesnosti

celé vlákno

No tak to už samozřejmě záleží jen na návrhu GUI, co přesně se má stát po úspěšném přidání uživatele ;-)

Jinak v jednom projektu to mám udělané tak, že do TempData ukládám záznam s klíčem „message“ a pokud je v TempData již uložená, kopíruji ji do ViewData. Master page šablona pak vypadá tak, že je připravena na zobrazení zprávy z ViewData (pokud je tam něco uložené). Tak mám jednoduše udělané, že každá stránka je schopna zobrazit jakoukoliv zprávu.

Ruthion Bisclaveret aura:91
13. 8. 2009 19:47 Nový

Re: Post-Redirect-Get (nejen) v ASP.NET MVC

celé vlákno

Redirekty a různé sofistikované ochrany před XSRF jsou pěkná věc, ale jen do chvíle, než opravdu potřebujete nějakou akci udělat 10× a místo 10-ti zmáčknutí F5 musíte 10× vyplňovat tatáž data. Proto mám raději po vyplnění formuláře stránku, na které je jen a pouze výsledek operace a bez redirektu (automatického).

Michal Augustýn
24. 11. 2010 20:10 Nový

Re: Post-Redirect-Get (nejen) v ASP.NET MVC

celé vlákno

Abych pravdu řekl, nikdy jsem tohle (jako uživatel) nepotřeboval.
Můj názor je takový, že když jste to někde potřeboval tak jsou (minimálně) dvě možnosti:
1) Dělal to tam každý uživatel a web byl tudíž blbě navržen, protože měl s tímto scénařem počítat.
2) Dělal jste to tam "jen vy", tedy byl to raritní případ, a pro ty IMHO nemá smysl optimalizovat.

Zasílat nově přidané příspěvky e-mailem