Monitorování stavu zařízení pomocí AJAXu
Článek není výukový kurz technologie AJAX, je to živá praktická ukázka použití technologie AJAX na intranetu výrobní firmy. V textu najdete ukázky kódu a poznámky s upozorněním na některá úskalí této technologie. Ke studiu do hloubky doporučuji sérii článků Mastering Ajax na serveru IBM developerworks.
Příklad je z intranetové aplikace tavení skla. Nad schématický obrázek sklářské vany jsou umístěny buňky (rámečky) pro zobrazení reálných procesních hodnot. Po načtení stránky se začnou přenášet a aktualizovat pouze reálná data (zde v intervalu 5 sec.), všechny ostatní prvky stránky zůstávají beze změny. Živá (reálná, okamžitá) data jsou uložena v databázi na serveru, tam je zapisuje řídící systém tavícího agregátu.
Základ ukázky pochází z roku 2001, v ukázce chybí původní DHTML popisy jednotlivých měřících míst a linky na stránky pro zobrazení trendů. Reálný čas odpovídá skutečnému času serveru, hodnoty měřených veličin zde nejsou z databáze, ale jsou vytvořeny pomocí generátoru náhodných čísel. Počet měřících míst je jen 4 oproti původním 16.
Podobně vypadá úvodní stránka vizualizační části řídícího systému tavení. I tato intranetová stránka může být zobrazena v prohlížeči několik hodin a stále zobrazuje reálná data. Pak stačí letný pohled na obrazovku pro zjištění, zda parametry výrobního procesu jsou v pořádku. Webové rozhraní aplikace nenabízí tak vysoký komfort jako řídící systém, ale nepotřebuje drahé licence, hardwarové klíče ani instalaci software. Vhodné pro občasnou kontrolu stavu tavení.
Kód CSS
Nejdříve několik poznámek ke kódu CSS. Buňky, pro zobrazení naměřených reálných hodnot využívají třídu Lb. V sekci CSS uvedeme jen definici základního vzhledu a rozměrů prvku. Pozice (umístění) jednotlivých buněk jsou určeny až v inline stylu.
<style type="text/css">
.Lb {font: 13px Arial, SansSerif, Verdana; text-align: center;
position: absolute; width: 45px; height: 15px;
border: 1px solid #ccc; background: #fff; color: #006;}
</style>
<body>
...
<div style="position: relative; width: 580px; height: 326px;">
<img src="tank.png" style="width: 580px; height: 326px;" />
<div class="Lb" style="top:35px; left: 216px; width: 60px;
border: 0; background: transparent;">real time:</div>
<div id="d0" class="Lb" style="top: 35px; left: 280px; width: 132px;"></div>
<div id="d1" class="Lb" style="top: 131px; left: 193px;"></div>
<div id="d2" class="Lb" style="top: 171px; left: 257px;"></div>
<div id="d3" class="Lb" style="top: 262px; left: 190px;"></div>
<div id="d4" class="Lb" style="top: 262px; left: 290px;"></div>
</div>
...
</body>
Schématický obrázek zařízení a buňky měřících bodů jsou umístěny do prvku <div>, který tvoří konteiner pro tyto prvky. Konteiner má pozici relative abychom mohli uvnitř tohoto konteineru umístit buňky měřících bodů do žádaného místa pomocí pozicování absolute, top a left. Umístění buněk (rámečků) jednotlivých měřících bodů odpovídá přibližně umístění senzorů. Každá buňka má přiděleno id podle pořadí jeho hodnoty v Ajax datovém souboru.
Skripty
Ladění Ajaxových skriptů je o poznání obtížnější než ladění skriptů pro DHTML, nebo pro validaci formulářů. Dílčí části skriptu běží na různých počítačích (klient-browser / server) a posílají si zprávy přes síť. První část skriptu vytvoří a pošle požadavek (běží v browseru), druhá část přijme požadavek, vytvoří a odešle odpověď (běží na serveru) a třetí část skriptu příjme a vyhodnotí odpověď (běží opět v browseru). Takovéto rozdělení skriptů dělá problémy při určení místa chyby.
Pokud provádíte vývoj na pracovní stanici pomocí IIS, počítejte s limitem připojených uživatelů. Maximálně jde ladit Ajax kód ve dvou současně spuštěných browserech (stránka s Ajaxem jsou dva uživatelé).
Skript v prohlížeči
Většina výukových článků používá podobný kód i s podrobným vysvětlením, proto uvedu jen nezbytný popis. Přenos dat je zajištěn pomocí objektu XMLHttpRequest, který může přenášet buď XML data, nebo prostý text. V tomto příkladu je přenášen prostý text. Celý přenos dat zajišťují dvě funkce: Next() provede vytvoření, inicializaci objektu req, nastaví zpracování odpovědi, odešle požadavek a nastaví timer pro opakování přenosu. Funkce processReq() testuje stav odpovědi, došlou odpověď zpracuje a vypíše přijatá data do příslušných buněk. Zbývá jen spustit celý proces, což provede poslední příkaz (řádek 30) po načtení celé stránky.
1. <script type="text/javascript">
2. var req, URL = "getStatus.asp";
3. function processReq() {
4. if(req.readyState == 4) {
5. if(req.status == 200) {
6. var data = "";
7. data = req.responseText.split("|");
8. for(i=0; i<5; i++) {
9. document.getElementById("d" + (i)).innerHTML = data[i];
10. }
11. }
12. }
13. }
14.
15. function Next() {
16. delete req;
17. if (window.XMLHttpRequest) { // IE7, FF, Opera, ...
18. req = new XMLHttpRequest();
19. }
20. else if (window.ActiveXObject) { // <=IE6
21. req = new ActiveXObject("Microsoft.XMLHTTP");
22. }
23. if(req) {
24. req.onreadystatechange = processReq;
25. req.open("POST", URL, true);
26. req.send(null);
27. window.setTimeout("Next()", 5000);
28. }
29. }
30. window.onload = Next;
31. </script>
Zpracování přijatých dat zajistí řádky 6-10. Nejdříve se datová řádka rozloží na jednotlivé hodnoty (řádek 7), potom se v cyklu (řádky 8, 9, 10) hodnoty zapíší do příslušných buněk měřících míst. Jako oddělovač dat je zde použit znak | (pipe) ve shodě s tím jako jsou data připravena na serveru. Pro zápis do buňky je použito id označení buňky, (např. id="d4") a funkce document.getElementById("d" + (i)). Vlastnost innerHTML není standardizovaná, ale umí ji všechny běžné browsery.
Skript záměrně neobsahuje odchytávání chybových stavů. Stránka buďto funguje, nebo ne. Pokud uživatel nemá možnost zjednat nápravu, nemá význam zobrazovat chybové zprávy.
Serverový skript
Na straně serveru skript přebírá parametry zaslané browserem podobně jako při příjmání dat z formuláře, nebo querystringu. V našem příkladu není potřeba žádný parametr, server má za úkol zaslat okamžitá data. Funkci serverového skriptu je dobré odladit samostatně, nezávisle na kódu browseru. Zadáním adresy serverového skriptu do adresního řádku browseru získáte zprávu. Tu kontrolujte přes zobrazení zdrojového kód stránky.
27.3.2007 21:14:30|1351|1446|361.2|721.6
Zde je ukázka výpisu dat zasílaných serverem. Všimněte si, že serverový skript nedoplňuje do zprávy žádné sekce typu html, head, nebo body. Zasílán je jen prostý text, jednotlivé položky jsou zde oddělené znakem pipe.
Vyrovnávací paměť, cache
Jeden z problémů technologie Ajax je vyrovnávací pamět cache browseru. Data získaná ze serveru browser uloží do paměti a při dalším dotazu již nečte data ze serveru, ale ze své vyrovnávací paměti.
To je výhodné např. při zobrazení mapy, problematické je to při zobrazení reálných dat jako v tomto příkladu. Proto musíme nastavit server tak, aby platnost odpovědi vypršela okamžitě. Nastavení je popsáno v článku IIS základní nastavení. ASP příkaz Response.AddHeader("Cache-Control", "no-cache") serverového skriptu také zamezí ukládání do vyrovnávací paměti browseru, to když nemáme fyzický přístup k IIS serveru.
Jiný postup jak si vynutit vždy nová data je vytvořit URL vždy s novým unikátním parametrem. Jako vhodný parametr může sloužit časový údaj (asi 13 místné číslo = počet milisekund někdy od roku 1970). Potom vložíme následující příkaz za řádek 24.
URL = "getStatus.asp?t=" + ((new Date()).valueOf());
Kódová stránka
Ajax předpokládá použití kódování UTF-8 pro přenos dat. Při přenosu jen číselných dat nebudou problémy. Přenos textových dat obsahující znaky s diakritikou problémy způsobit může. Datová zpráva musí být v kódu UTF-8, jinak se místo znaků s diakritikou zobrazují otazníky. Znaky s diakritikou v tomto kódu zabírají více bytů a to ovlivní návrh databáze, stanovení délky textových polí, abecední řazení, vyhledávání a také testy maximální délky vstupních polí formulářů.
Tento problém mě trápil před několika lety při programování formuláře s kaskádovými select prvky. Jejich obsah se dynamicky načítal podle výběru předchozího select prvku. Někdy se zobrazila normální čeština, jindy čeština s otazníky. Nakonec jsem od Ajax řešení upustil.
Ajax omezení
XMLHttpRequest objekt v browseru lze využít jen pro přenos dat pod jednou doménou. Tedy skript může žádat data jen z toho serveru, ze kterého pochází původní Ajax stránka, nebo ze serveru, který je ve stejné doméně. Pro čtení dat ze vzdáleného serveru je nutné použít objekt Ajax na serveru.
updated 14.04.2007