JavaScript und Nginx = nginScript und HTTP2 zum Booten


    Es war am Abend, es gab nichts zu tun, aber der Kopf gab keine Ruhe und wollte etwas für die Seele ... Und für die Seele wollte ich etwas Neues, irgendwie Ungewöhnliches.

    Ich, wie viele der Bürger von Khabrovsk, liebe neue Gegenstände. Die Veröffentlichung neuer Software ist wie ein Feiertag. Neue Funktionen, neue Funktionen ... Neue Methoden zum Einschlagen von Nägeln und Fahrradfahren. Neue Fahrräder ... Im Allgemeinen können Sie sich eine Reihe von Allegorien und Metaphern einfallen lassen. Und wovon rede ich? Ach ja, zu Nginx, HTTP2 und JavaScript. Was haben sie damit zu tun, fragst du? Und die Tatsache, dass in der neuesten Version von Nginx (1.9.5) viele interessante Brötchen hinzugefügt wurden, nämlich:

    • das HTTP2-Protokoll hinzugefügt und das SPDY-Modul entfernt (siehe den alten Müll)
    • Integrierte das Modul ngx_http_js_module direkt in nginx und erstellte Ihren eigenen JavaScript-Dialekt

    Ich werde Ihnen die Details mitteilen.

    Eigentlich haben mich diese beiden Features interessiert. Ich bin ein erfahrener Krieger, der von einem Lager (Tippfehler nach Freud - ich liebe Lager und dunkles Bier) der Beckender auf die Front-End-Seite gewechselt ist. Aber ich verfolge weiterhin meine Lieblingswerkzeuge, einschließlich Ngnix.

    Über HTTP2


    Ich werde nicht viel reden. Es funktioniert. Und die Konfiguration ist einfacher als für SPDY. Na ja, oder ähnlich. Fügen Sie den Parameter während der Konfiguration hinzu, um einen Server mit HTTP2-Unterstützung zu erstellen:

    	--with-http_v2_module
    

    Und alle. Alles ist einfach, keine Patches und Libs von Drittanbietern, nur eine Zeile bei der Konfiguration vor der Montage. Auf einem Hub finden Sie Informationen zu HTTP2:

    1. HTTP2 Erklärung
    2. Testversion des HTTP / 2-Moduls für NGINX veröffentlicht

    Über JavaScript


    Oh, das ist der lustige Teil! Frontenders, ich beeile mich Ihnen mitzuteilen, dass wir einen neuen JavaScript-Dialekt haben (na ja, wir werden uns nicht daran gewöhnen, wenn wir das wollen) - das ist nginScript (englisches Skript). Hurra! Ich wusste immer, dass alles wie Nägel aussieht, wenn ein Programmierer ein Mikroskop hat. Ein Witz, liebe Programmierer, ein Witz.

    JavaScript-Skripte können direkt in der Konfigurationsdatei (!) Verwendet werden, um eine erweiterte Logik für die Verarbeitung von Anforderungen zu definieren. Eine Konfiguration bilden, eine Antwort dynamisch generieren. Sie können auch die Anforderung und die Antwort ändern. Und Sie können schnell Stubs mit Problemlösungen in Webanwendungen erstellen (auch als „Krücken“ bezeichnet) oder diese vorübergehend ausführen und dann wie gewünscht wiederholen. Dies ist nur eine kleine Wendung, ich sage es Ihnen!

    Das Skript selbst wird mit der Direktive js_run gestartet und ermöglicht es direkt auf der Serverseite (was trage ich?) ... Nein, direkt auf dem Server selbst können viele Operationen auf niedriger Ebene mit der Anfrage ausgeführt werden, ohne dass ein separates Modul in C / Lua geschrieben und dort gelöst werden muss solche Aufgaben.

    Zur Ausführung der Skripte wird die eigene njs-Engine verwendet. Zu diesem Zweck implementierte das Nginx-Entwicklungsteam seine Version der virtuellen Maschine unter einer abgeschnittenen Teilmenge der JavaScript-Sprache. Eigentlich hieß diese Sprache nginScript, um nicht mit JavaScript zu verwechseln, da es sich dennoch um eine Teilmenge handelt. Was interessant ist: Für jede Anforderung wird eine separate virtuelle Maschine gestartet, sodass kein Garbage Collector erforderlich ist. JavaScript ist als beliebteste Programmiersprache ausgewählt. Lua war eine gute Anwärterin, aber sie ist in den Kreisen der Webentwickler nicht so verbreitet. Die Notwendigkeit, eine eigene virtuelle JavaScript-Maschine zu erstellen, beruht auf der Tatsache, dass vorhandene Engines für die Arbeit in einem Browser optimiert sind, während Nginx nicht nur eine Serverimplementierung erfordert, sondern auch eine in die Engine integrierte. In der Regel haben die Entwickler nicht die volle V8 gezogen. Daher ist dies JavaScript, aber Sie müssen wie unter IE6 schreiben, ohne anzugeben. Trotzdem ist dies eine Konfig, wenn das so ist.

    NginScript verfügt über eine virtuelle Maschine und einen Bytecode-Compiler mit Schnellstart und -abschaltung. Blockierungsvorgänge, wie z. B. HTTP-Unterabfragen, können ähnlich wie bei anderen Blockierungsvorgängen in JS angehalten und fortgesetzt werden.

    Der Nginx-Konfigurationsbeschreibungssprache wurden Syntaxanweisungen hinzugefügt, mit denen Sie JS-Codeblöcke direkt in die Konfigurationsdatei einbetten können. Solche Blöcke werden ausgeführt, wenn HTTP-Transaktionen verarbeitet werden, und ermöglichen es, dass jede Anforderung Vorgänge wie das Anpassen der internen Nginx-Parameter, das Erstellen komplexer Bedingungen, das Ändern der Anforderung oder der Antwort ausführt.

    Mit nginScript können Sie Konfigurationen beschreiben, die ohne das Schreiben zusätzlicher Erweiterungen und Module böswillige Anforderungen, die Schwachstellen in Webanwendungen ausnutzen, dynamisch blockieren oder die Intensität bestimmter Anforderungen begrenzen können. Es ist auch möglich, flexible Verkehrsumleitungsregeln zu implementieren, die Informationen aus der Anforderung verwenden und nicht nur.

    Und Sie können heiße Krücken machen! Wir können Fehler in Webanwendungen korrigieren, die Geschäftslogik ändern, Anforderungen an mehrere Server verteilen, die Antworten von diesen zusammenfassen und vieles mehr ... Und das alles stimmt in der Konfiguration. Und das alles in der vertrauten Sprache, die wir lieben.

    Also, viele Buchen, fahren wir mit der Installation und den Beispielen fort.

    Installation


    Wenn Quecksilber nicht installiert ist - einstellen. Und dann folgen Sie den Anweisungen:

    # Obtain the latest source for NGINX from http://nginx.org/en/download.html
    $ wget http://nginx.org/download/nginx-1.9.5.tar.gz
    $ tar -xzvf nginx-1.9.5.tar.gz
    # Obtain the development sources for nginScript
    $ hg clone http://hg.nginx.org/njs
    # Build and install NGINX
    $ cd nginx-1.9.5
    $ ./configure \
            --sbin-path=/usr/sbin/nginx \
            --conf-path=/etc/nginx/nginx.conf \
            --pid-path=/var/run/nginx.pid \
            --lock-path=/var/run/nginx.lock \
            --error-log-path=/var/log/nginx/error.log \
            --http-log-path=/var/log/nginx/access.log \
            --user=www \
            --group=www \
            --with-ipv6 \
            --with-pcre-jit \
            --with-http_gzip_static_module \
            --with-http_ssl_module \
            --with-http_v2_module \
            --add-module=../njs/nginx \
    \
    $ make -j2 && make install
    

    NginScript aka JavaScript


    Wir können Variablen mit Berechnungsergebnissen durch die Anweisung js_set vordefinieren :

    js_set $js_txt "
       var m = 'Hello ';
       m += 'world!';
       m;
    ";
    server {
        listen :443 ssl http2;
        server_name edu.tutu.ru;
        set $sname edu.tutu.ru;
        set $root "/www/sites/$sname/www/public";
        ssl_certificate        /etc/nginx/ssl/edu.tutu.ru.pem;
        ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key;
        include base.conf;
        location /helloworld {
            add_header Content-Type text/plain;
            return 200 $js_txt;
         }
    }
    

    Wie Sie sehen, wird eine ungewöhnliche Anweisung als Rückgabewert verwendet. Es ist seltsam, warum sie das Wort nicht zurückbrachten. Direkt unerwartet und ungewöhnlich. Aber komm schon, sie haben es geschafft.

    Soweit ich weiß, kann die Direktive auch außerhalb von Serverblöcken installiert werden. Ansonsten schwört der Parser.

    Sie können Inhalte sofort aus der Konfiguration generieren und an den Browser senden:

    location /helloworld {
        js_run "
            var res;
            res = $r.response;
            res.contentType = 'text/plain';
            res.status = 200;
            res.sendHeader();
            res.send('Hello, world!');
            res.finish();
        ";
    }
    

    Lass uns http_dump machen, m?

    js_set $http_dump "
        var a, s, h;
        s  = 'Request summary\n\n';
        s += 'Method: ' + $r.method + '\n';
        s += 'HTTP version: ' + $r.httpVersion + '\n';
        s += 'Host: ' + $r.headers.host + '\n';
        s += 'Remote Address: ' + $r.remoteAddress + '\n';
        s += 'URI: ' + $r.uri + '\n';
        s += 'Headers:\n';
        for (h in $r.headers)
            s += '  header \"' + h + '\" is \"' + $r.headers[h] + '\"\n';
        s += 'Args:\n';
        for (a in $r.args)
            s += '  arg \"' + a + '\" is \"' + $r.args[a] + '\"\n';
        s;
    ";
    server {
        listen :443 ssl http2;
        server_name edu.tutu.ru;
        set $sname edu.tutu.ru;
        set $root "/www/sites/$sname/www/public";
        ssl_certificate        /etc/nginx/ssl/edu.tutu.ru.pem;
        ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key;
        location /js/httpdump {
            add_header Content-Type text/plain;
            return 200 $js_summary;
        }
    }
    

    Und schreiben wir einen Service zur Berechnung von Fibonacci-Zahlen


    Wenn es ein Mikroskop gibt, warum dann nicht einen Nagel hämmern? Auf die Frage, warum, antwortet immer ein echter Programmierer / Wissenschaftler / Erfinder: Weil ich es kann! Ja, ich kann einen solchen Dienst schreiben, ohne die Nginx-Konfiguration zu verlassen, ohne Nodejs, PHP oder Ruby zu installieren. Ich kann das alles im Server machen! Ja

    location /js/getfib {
        js_run "
            function fib(n) {
                var prev = 1,
                    curr = 1,
                    newc,
                    i;
                if (n < 2) return n;
                for (i = 3; i <= n; i++) {
                    newc = prev + curr;
                    prev = curr;
                    curr = newc;
                }
                return curr;
            }
            var n = +$r.args['n'],
                txt = 'Fibonacci( ' + n + ' ) = ' + fib(n),
                res = $r.response;
            res.contentType = 'text/plain';
            res.status = 200;
            res.sendHeader();
            res.send(txt);
            res.send('\n');
            res.finish();
        ";
    }
    

    Ich wollte stattdessen schreiben:

    newc = prev + curr;
    prev = curr;
    curr = newc;
    

    gebrochener Code:

    [ prev, curr ] = [ curr, prev + $curr ];
    


    Aber nginScript weiß nichts über ES2015 / ES6. Dann schrieb ich so:

    prev = [ curr, prev += curr ][0];
    

    Und es gab auch einen Feil. Es stellt sich heraus, dass auch das Schreiben unmöglich ist. Also Freunde, nicht alles ist möglich. Man erhält eine Art IE5. Aber insgesamt hat es mir gefallen.
    Gut zu dir, was du gerade da hast.

    Verwandte Links




    UPD

    Ein Beispiel für das Binden von Upstream- und dynamischem Routing


    upstream my_upstream0 {
        server server1.example.com;
        server server2.example.com;
    }
    upstream my_upstream1 {
        server server3.example.com;
        server server4.example.com;
    }
    js_set $my_upstream "
        var s, upstream, upstream_num;
        upstream = $r.args.upstream;
        // convert upstream number to integer
        upstream_num = +upstream | 0;
        if (upstream_num < 0 || upstream_num > 1) {
            upstream_num = 0;
        }
        s = 'my_upstream' + upstream_num;
        s;
    ";
    server {
        listen 80;
        location / {
            proxy_set_header Host $host;
            proxy_pass http://$my_upstream;
        }
    }
    

    Jetzt auch beliebt: