Návod k použití Node.js na FI

Běhové prostředí Node.js slouží k vytváření programů v jazyce JavaScript. Tato platforma je primárně určena pro běh samostatných serverů poslouchajících na dedikovaném TCP portu, což platí i pro webové frameworky. Existují ale moduly, které umožňují běh pod webovým serverem Apache a tedy i na Aise na adrese www.fi.muni.cz. Po přečtení tohoto textu byste měli mít dost informací pro to, abyste zvolili pro vás vhodné řešení.

Než budete pokračovat, doporučujeme vám prostudovat si návody Uživatelské HTML stránky, Vytváření CGI skriptů, a Návod k použití PHP na FI. Předpokládáme, že Apache má přístup do adresáře public_html.

CGI

CGI je jednoduché rozhraní, které lze využít v libovolném programovacím jazyce. V tomto návodu využijeme modul cgi-node, který poskytuje základní funkce pro jednodušší práci s HTTP požadavky a odpověďmi.

Nejprve vytvoříme adresáře pro naši novou aplikaci a podpůrné programy:

mkdir --parents ~/public_html/node-app/cgi-bin

Stáhneme knihovnu cgi-node a nastavíme jí právo na spuštění:

cd ~/public_html/node-app/cgi-bin
wget -O cgi-node.cgi https://github.com/DEDAjs/cgi-node/releases/download/v0.2/cgi-node.js
chmod u+x cgi-node.cgi

Pak v ní změníme cestu k Node.js binárce na prvním řádku na /usr/bin/node a nastavíme cestu k adresáři se session soubory (proměnnou SessionPath) na /tmp:

sed -i "1s|.*|#!/usr/bin/node|" cgi-node.cgi
sed -i "s|SessionPath:.*|SessionPath: '/tmp/'|" cgi-node.cgi

Samotnou aplikaci uložíme do souboru index.js. Zavoláme v ní jen funkci CgiNodeInfo(), která se hodí pro testování a vypisuje informace o prostředí, HTTP dotazu a session:

cd ~/public_html/node-app
echo "CgiNodeInfo();" > index.js

Jednoduchou "Hello world" aplikaci byste napsali takto:

response.headers['Content-Type'] = 'text/plain; charset=utf-8';
write("Hello world!\n");

Více podrobností o použití node-cgi zjistíte v dokumentaci nebo ve zdrojovém kódu cgi-node.js.

Nakonec řekneme webovému serveru Apache, že má všechny soubory s příponou .js spouštět pomocí cgi-node.cgi. Zde i v dalším textu nahraďte xlogin vlastním loginem.

cd ~/public_html/node-app
cat > .htaccess <<'EOF'
AddHandler cgi-node .js
Action cgi-node /~xlogin/node-app/cgi-bin/cgi-node.cgi
DirectoryIndex index.js
EOF

Ověřte funkčnost aplikace navštívením https://www.fi.muni.cz/~xlogin/node-app/index.js.

V aplikaci můžete využít i další moduly. Buď zadejte plnou cestu k nim (/home/xlogin/...) nebo je instalujte do adresáře ~/public_html/node-app/cgi-bin, protože se hledají relativně k umístění cgi-node.cgi:

cd ~/public_html/node-app/cgi-bin
npm install wonderful-module

FastCGI

Při použití CGI brzy narazíte na limity této technologie. Každý HTTP požadavek je zpracován nově spuštěným procesem, což v případě Node.js znamená poměrně velkou latenci. Navíc nemůžete využít žádný z řady frameworků, které ke svému fungování potřebují modul http.

Naštěstí existuje modul node-fastcgi, který je postaven na specifikaci FastCGI. Tato umožňuje webovému serveru nechat dlouhodobě spuštěný proces obsluhovat více HTTP požadavků po sobě.

Nejprve si připravte adresář s aplikací, ve kterém nainstalujte modul node-fastcgi:

mkdir --parents ~/public_html/node-fastcgi-app
cd ~/public_html/node-fastcgi-app
npm install node-fastcgi

Samotná aplikace index.js může vypadat takto (převzato z dokumentace):

#!/usr/bin/node

var fcgi = require('node-fastcgi');

var server = fcgi.createServer(function(req, res) {
    if (req.method === 'GET') {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end("Hello, world!\n");
    } else if (req.method === 'POST') {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        var body = "";

        req.on('data', function(data) { body += data.toString(); });
        req.on('end', function() {
            res.end("Received data:\n" + body);
        });
    } else {
        res.writeHead(501);
        res.end();
    }
});
server.listen();

Skriptu je nutné dát práva pro vykonání (x) pro vlastníka:

chmod u+x index.js

Nakonec řekneme webovému serveru Apache, že má .js soubory spouštět pomocí FastCGI:

cat > .htaccess <<'EOF'
AddHandler fastcgi-script .js
AddType application/x-httpd-javascript .js
DirectoryIndex index.js
EOF

Vyzkoušet její funkčnost můžete na adrese https://www.fi.muni.cz/~xlogin/node-fastcgi-app/.

Express

FastCGI server můžete použít jako náhradu za modul http. Jako příklad uvedeme použití s frameworkem Express. Tento framework nejdříve nainstalujeme (platí poznámky o umístění modulů ze sekce CGI — hledají se relativně ke skriptu):

cd ~/public_html/node-fastcgi-app
npm install express

Aplikace pak může vypadat následovně:

#!/usr/bin/node

var fcgi = require('node-fastcgi');
var express = require('express');
var app = express();

app.get('/~xlogin/node-express-app/', function (req, res) {
    res.set('Content-Type', 'text/plain');
    res.send("Hello World!\n");
});

fcgi.createServer(app).listen();

a dostupná bude na https://www.fi.muni.cz/~xlogin/node-express-app/.

Pěkná URL

Aby se vám a uživatelům vaší aplikace dobře pracovalo s URL, doporučujeme nastavit si v souboru .htaccess přepisování URL pomocí mod_rewrite:

cat >> .htaccess <<'EOF'
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/~xlogin/node-express-app/index.js
RewriteRule (.*) /~xlogin/node-express-app/index.js/$1 [L,PT]
EOF

Zde řádek s RewriteRule zajišťuje, že URL tvaru www.fi.muni.cz/~xlogin/node-express-app/LIBOVOLNY_SUFFIX budou obsloužena aplikací uloženou v index.js. Řádek s RewriteCond zabraňuje nekonečnému cyklu přepisování.

Vaši aplikaci můžete například napojit metodou use pod daný prefix a používat tak cesty nezávislé na konkrétním umístění aplikace:

#!/usr/bin/node

var prefix = '/~xlogin/node-express-app';
var fcgi = require('node-fastcgi');
var express = require('express');
var base_app = express();
var app = express();

app.get('/hello', function (req, res) {
    res.set('Content-Type', 'text/plain');
    res.send("Hello\n");
}); 

app.get('/world', function (req, res) {
    res.set('Content-Type', 'text/plain');
    res.send("World!\n");
}); 

base_app.use(prefix, app);

fcgi.createServer(base_app).listen();

Vyzkoušet můžete adresy https://www.fi.muni.cz/~xlogin/node-fastcgi-app/hello a https://www.fi.muni.cz/~xlogin/node-fastcgi-app/world.

© Text věnující se CGI vychází z návodu Patrika Vala.