Pohled do hlubin webserverovy duše (aneb jak fungují HTTP moduly a handlery)

Kromě psaní klasických ASP.NET stránek (ASPX) je možné webové aplikace psát ještě "o úroveň níž", tedy pomocí HTTP handlerů a modulů. Je to jediná možnost jak implementovat některé funkce a nejpraktičtější možnost jak implementovat mnohé jiné. V tomto spíše teoretickém článku si povíme, jak vlastně funguje komunikace .NET s Internet Information Services a kde do toho můžeme jako programátoři zasahovat.

Jak funguje web server

Web server komunikuje s okolím prostřednictvím protokolu HTTP. Velmi zjednodušeně transakce probíhá nějak takhle:

  1. Klient se připojí na server a řekne "chci z webu www.aspnet.cz soubor /_gfx/mvp.png".
  2. Server se podívá do své konfigurace a zjistí, že WWW root pro server jménem www.aspnet.cz ukazuje do fyzického adresáře C:\InetPub\wwwroot\, a že se tedy požadovaný soubor nachází na fyzické cestě C:\InetPub\wwwroot\_gfx\mvp.png.
  3. Na základě shora uvedeného zjištění uchopí předmětný soubor, pošle ho klientovi a ukončí spojení.

Pokud bychom napsali web server podle výše uvedených zásad (což je triviální), sice by fungoval, ale uměl by posílat jenom statické stránky, předávat soubory bez jakékoliv další funkcionality.

A proto se už v dobách, kdy byly počítače dřevěné a šlapací, objevily takzvané CGI skripty. Jejich princip je geniálně jednoduchý: pokud byl požadovaný soubor program, tak místo aby se odeslal klientovi, spustil se a klientovi se poslal jeho výstup. Programování webových aplikací tímto způsobem má pravda i své výhody (je jednoduché pro někoho, kdo umí programovat klasické konzolové aplikace), ale nevýhody často převažují: nízký výkon, komplikovaná údržba, možné ohrožení bezpečnosti...

Proto spatřila světlo světa technologie ISAPI. S jistým zjednodušením jest možno říci, že se jedná o univerzální technologii, která umožňuje předávat HTTP požadavky rozličným komponentám (říká se jim ISAPI filtry), aby si s nimi poradily jak umí.

Klasickým případem z internetového dávnověku může být technologie SSI: Vložením speciální direktivy (pokud mne paměť neklame, je to <!--#include file="jmenosouboru"-->) do HTML souboru bylo možno na straně serveru vložit do HTML kódu jiný soubor (příkladně vždy se opakující navigaci) a výsledek odeslat.

ISAPI v IIS 6

Od té doby se technologie poněkud vyvinula a na vrcholu je nyní technologie .NET. Podíváme-li se na Microsoft Internet Information Services 6.0 (web server ve Windows 2003), zpracovávají se HTTP požadavky na .NET aplikace nějak takhle (klepnutím na obrázek otevřete jeho větší verzi):

Schéma zpracování HTTP požadavku v IIS 6 - popis v textu

Na samém počátku je IIS. Jeho konfigurace je uložena v Metabázi (fyzicky se jedná o soubor %SYSTEMROOT%\System32\inetsrv\MetaBase.xml). Kromě mnoha jiných je tam také uložena informace který virtuální server (určený kombinací IP adresy, portu a hostname) ukazuje na kterou oblast (složku) disku a jaké ISAPI moduly se mají na jaké soubory aplikovat.

Posledně zmíněné nastavení je závislé na příponě serveru. IIS tak mapuje soubory s příponou .asp na ASP.DLL (ISAPI filtr pro klasické ASP 3.0), soubory s příponami .aspx, .ascx, .asmx  a podobně na ASPNET_ISAPI.DLL (totéž pro ASP.NET), výše zmíněné server-side includes soubory .shtml, .shtm a .stm na SSINC.DLL a podobně.

Z výše zmíněného vyplývá, že ASP.NET engine (a tedy ani vaše aplikace) se nedozví o požadavcích, které byly učiněny na soubory, jejichž přípony nejsou namapovány na ASPNET_ISAPI.DLL. Veškeré techniky popsané v tomto článku, jakož i v jeho pokračováních, tedy můžete použít jenom na soubory s mapovanými příponami. Pokud tedy chcete např. napsat HTTP handler který bude automaticky zmenšovat JPG obrázky, musíte příponu .jpg namapovat v konfiguraci IIS stejně jako např. .aspx.

Wildcard application maps

IIS 6.0 přináší novinku, která umožňuje výše zmíněné omezení obejít - wildcard application maps. Pomocí ní můžete nastavit, aby se veškeré požadavky zpracovávaly prostřednictvím nějakého ISAPI filtru. Pokud tedy nastavíte toto mapování na ASPNET ISAPI filtr (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll), budou se veškeré požadavky zpracovávat pomocí ASP.NET engine a budete do nich moci zasahovat.

Shora uvedenou technologii používá např. můj systém SilverWolf (živé nasazení příkladně v mé fotogalerii), když automaticky generuje HTML a náhledy při požadavcích na adresáře, obrázky nebo soubory s příponou .xhtml.

Pokud chcete pro daný web wildcard mapping nastavit, otevřete si v IIS Manageru jeho vlastnosti a na záložce Home directory klepněte na Application Settings -> Configuration. Kromě obvyklého mapování máte možnost přidat i wildcardové. Pokud zrušíte zaškrtnutí pole Verify that file exists, nebude IIS ověřovat ani zda požadovaný soubor existuje, než zavolá ISAPI engine.

ASP.NET Pipeline

Rozhodne-li se IIS že o blaho zadaného požadavku by se měl dále přičiniti ISAPI engine pro ASP.NET, může do toho začít mluvit vaše aplikace. Zde totiž ztrácí svou konfigurační moc metabáze a získává ji konfigurace .NET, jmenovitě soubory Machine.Config a Web.Config. Zjednodušeně řečeno: Machine.Config nastavuje parametry pro celý server, Web.Config může pro určitou aplikaci tato nastavení doplnit či přepsat. Pokud tak neučiní, použijí se nastavení z Machine.Config. Pomocí těchto souborů můžete, jak si povíme v následných článcích, do hry zapojit vlastní HTTP moduly a handlery.

GLOBAL.ASAX a HTTP moduly poprvé

Jako první se odpálí patřičné události (znáte lepší překlad pro firing event? ;-) definované v GLOBAL.ASAX - typicky se jedná například o oblíbenou událost BeginRequest a podobně.

Dále přijdou na řadu zkonfigurované HTTP moduly. Pro tento okamžik si je můžete představit jako nezávislé knihovny (aplikace o nich fakticky nemusí vůbec vědět a nemůže jim do činnosti moc mluvit), které se napojí na události aplikace a dělají prakticky totéž co GLOBAL.ASAX.

HTTP moduly se používají například pro autentizaci a autorizaci. Používáte-li například Forms Authentication, vězte že její funkčnost je zajištěna právě HTTP modulem. Nic vám tedy nebrání v tom, abyste si napsali vlastní autentizační modul a používali ho místo ní (příklad - v angličtině - najdete na webu SAMS publishing).

V tomto okamžiku máme možnost víceméně libovolně měnit obdržený požadavek. Hezkým příkladem je například takzvaný url rewriting. Z přirozenosti ASP.NET skriptů vyplývá, že je nejsnazší jsou-li volány nějak jako /Clanek.aspx?id=123. Tento postup ovšem není příliš v oblibě u uživatelů a vyhledávačů, neb ti mají rádi "hezká" URL. Mnohem lepší by bylo, kdyby adresa vypadala nějak jako /Clanky/123.aspx. Ovšem spravovat smečku autogenerovaných ASPX souborů není nic moc. Proto v rámci HTTP modulu můžeme nastavit, že se všechny adresy /Clanky/neco.aspx přepíší na /Clanek.aspx?id=neco. Shora uvedené nastane v rámci serveru, klient se o tom vůbec nedozví. Chcete praktický příklad? Podívejte se na adresu článku, který právě čtete.

HTTP handler

Poté, co moduly dokončí svou práci, zavolá se odpovídající handler (odpovídající podle nastavení v .Config souborech). To je "konečná instance", třída jejímž smyslem je vygenerovat vlastní obsah stránky a poslat ho na klienta.

Typickým příkladem může být například zpracování souborů s příponou ASPX: konečnou instancí pro ně je HTTP handler, který přečte zdrojový soubor z disku a vykoná k němu přiložený kód (ať už inline nebo backend). Jiným příkladem je třeba handler, který se vyvolá při dotazu na jakýkoliv soubor s příponou .Config - ten je o hodně jednodušší, protože bez ohledu na cokoliv dalšího prostě vygeneruje chybové hlášení na téma že do konfiguračních souborů nikdo nemá co lézt.

GLOBAL.ASAX a HTTP moduly podruhé

Poté co handler dokončí svou práci, dění se vrací zpět do rukou HTTP modulů a GLOBAL.ASAX. Odpálí se další eventy, ve kterých je možno pracovat s výstupem, který handler vygeneroval, a nějak ho dále měnit.

Hezkým příkladem takového modulu může být například rozkošné dílko mého MVP kolegy Eduarda A. Morcilla. Pomocí HTTP modulu transparentně šifruje a dešifruje parametry předávané prostřednictím QueryStringu.

Shrnutí

HTTP požadavky mohou být v rámci IIS zpracovávány různými ISAPI filtry. IIS rozhoduje o tom, které to budou, na základě vlastní konfigurace a přípony souboru, případně wildcard mappingu.

Pokud je použit ISAPI modul pro ASP.NET, lze do průběhu vyřizování požadavků zasahovat prostřednictvím HTTP modulů a HTTP handlerů. Moduly lze vrstvit "na sebe" a obvykle se používají k modifikování HTTP požadavku nebo odpovědi, například k autentizaci nebo autorizaci. HTTP handler je vždy právě jeden a je odpovědný za "obvyklou práci", tedy vlastní vygenerování odpovědi na uživatelův požadavek.

V dalších článcích si povíme o tom, jak je možno psát a používat vlastní HTTP handlery a moduly.

Titulek:
Text komentáře:
Vaše jméno:
Váš e-mail: (nebude zveřejněn)

WWW stránka:
Opište text z obrázku:
odpovědětodpovědět Gravatar

rychlost

8.4.2005 18:26:138.4.2005 18:26:13 matobmatob ---.dsl.nextra.sk

V clanku pisete ze cgi scripty sa vyznacovali nizkym vykonom. Ja som bol vzdy presvedceny o opaku... tak ako to je?

Momentalne potrebujem spravit nieco fakt rychle. V podstate klasicku stranku ktora bude mat len jednu funkciu a to vratit uzivatelovi nejake data. Problem je vtom ze to bude enormne zatazovane. Dalo by sa to prirovnat napr k newlinx.sk a stranke ktora vracia banner. Myslim ze oni to maju tak ze sa vola priamo DLL.

Neviete niekto poradit ako nieco take spravit v NETku?

To o CGI skriptech jsem psal v souvislosti s Windows platformou - tady se spouštěl klasický proces, a spuštění procesu na Windows znamená vždycky docela velkou režii. Nevylučuji, že na jiných OS to může být jinak.

U zatěžovaných systémů se používaly třeba ISAPI filtry, protože v porovnání se skriptovacím jazykem (ASP 3.0) bylo sice těžké je napsat, ale byly-li napsané dobře, fungovalo to výkonně. ASP.NET jsou výkonné samy o sobě.

Pokud se týče vašeho zadání, tam záleží na tom, co to vlastně dělá. Obecně za nejvýkonnější na Windows platformě považuji ASP.NET. Pokud vaše použití umožňuje použití nějaké formy cacheování, bude to zase rychlejší atd.

odpovědětodpovědět Gravatar

re

9.4.2005 14:41:419.4.2005 14:41:41 matobmatob ---.dsl.nextra.sk

Urcite to chcem robit na NET platforme, len hladam najrychlejsie riesenie. Ked to bude cez ASP.NET urcite su tam aj nejake vedlajsie rezijne zatazenie.

Jak říkám: Záleží na tom, co chcete aby to dělalo. Pokud je pro vás zbytečná infrastruktura ASP.NET, můžete si například napsat vlastní handler.

odpovědětodpovědět Gravatar

RE: re

11.4.2005 11:31:2111.4.2005 11:31:21 matobmatob ---.dsl.nextra.sk

Potrebujem spraviť spraviť jednu stránku (alebo nieco ine) ktorá uloží a načíta pár záznamov z db a vygeneruje nejaký javascript. V podstate nič zložíté.

Bude sa to používať na viacerých weboch, v podstate niečo ako výmenná reklama. Čiže predpokladám veľkú záťaž.

Takže hľadám pre to najvhodnejšie riešenie.

odpovědětodpovědět Gravatar

RE: re

15.4.2005 18:59:5515.4.2005 18:59:55 matobmatob ---.dsl.nextra.sk

Co keby som to spravil ako HttpHandler alebo HttpModul?

Ano, může být lepší udělat to jako ASHX (handler) místo ASPX (stránka), pokud nepotřebujete celou tu opičárnu ohledně formulářů a podobně.

odpovědětodpovědět Gravatar

rozdiel?

19.4.2005 18:59:0319.4.2005 18:59:03 MikiMiki ---.dsl.nextra.sk

Aky je zasadny rozdiel medzi modulom a handlerom? Z clanku som to celkom nepochopil.

HTTP handler je "poslední instance" stará se o zpracování konkrétního souboru/typu souboru. HTTP modul je "nad ním", zpracovává všechny příchozí požadavky ještě předtím než se dostanou k handlerům a potom zase výstupy co z toho handleru vylezou.

Všechno, co uděláš v handleru, můžeš napsat i v modulu (leč poněkud komplikovaněji), ale naopak to neplatí.

  • Altairis
  • Nemesis
  • Microsoft MVP
  • IIS
  • ASP.NET