njs API

Этот перевод может быть устаревшим. Смотрите английскую версию для ознакомления с последними изменениями.
HTTP
     Запрос
Stream
     Сессия
Примеры
     Декодирование URL
     Кодирование URL
     Возврат самого быстрого ответа от прокси
     Создание HS JWT
     Доступ к API при помощи подзапроса
     Создание хэша secure_link

njs предоставляет объекты, методы и свойства для расширения функциональности nginx.

HTTP

Объект HTTP доступен только в модуле ngx_http_js_module. Все строки в объекте HTTP являются байтовыми строками.

Запрос

r.args{}
объект аргументов запроса, только чтение
r.error(строка)
записывает строку в лог-файл ошибок на уровне лога error
r.finish()
завершает отправку ответа клиенту
r.headersIn{}
объект исходящих заголовков, только чтение.

Например, доступ к заголовку Header-Name можно получить при помощи синтаксиса headers['Header-Name'] или headers.Header_name

r.headersOut{}
объект исходящих заголовков, доступно для записи.

Например, доступ к заголовку Header-Name можно получить при помощи синтаксиса headers['Header-Name'] или headers.Header_name

r.httpVersion
версия HTTP, только чтение
r.log(строка)
записывает строку в лог-файл ошибок на уровне лога info
r.method
HTTP метод, только чтение
r.parent
ссылается на родительский объект запроса
r.remoteAddress
адрес клиента, только чтение
r.requestBody
хранит тело запроса, только чтение
r.responseBody
хранит тело ответа подзапроса, только чтение
r.return(код[, строка])
отправляет клиенту полный ответ с указанным кодом

Можно задать или URL перенаправления (для кодов 301, 302, 303, 307 и 308), или текст тела ответа (для остальных кодов) в качестве второго аргумента

r.send(строка)
отправляет часть тела ответа клиенту
r.sendHeader()
отправляет заголовок HTTP клиенту
r.status
статус, доступно для записи
req.variables{}
объект переменных nginx, только чтение
r.warn(строка)
записывает строку в лог-файл ошибок на уровне лога warning
r.uri
текущий URI, только чтение
r.subrequest(uri[, options[, callback]])
создаёт подзапрос с заданными uri и options и устанавливает необязательный callback завершения.

Если options является строкой, то в ней содержится срока аргументов подзапроса. В противном случае ожидается, что options является объектом со следующими ключами:

args
строка с аргументами
body
тело запроса
method
метод HTTP

callback получает объект ответа подзапроса с методами и свойствами, идентичными родительскому объекту запроса.

Stream

Объект stream доступен только в модуле ngx_stream_js_module. Все строки в объекте stream являются байтовыми строками.

Сессия

s.remoteAddress
адрес клиента, только чтение
s.eof
логическое свойство, true, если текущий буфер является последним буфером, только чтение
s.fromUpstream
логическое свойство, true, если текущий буфер является буфером от проксируемого сервера к клиенту, только чтение
s.buffer
текущий буфер, доступен для записи
s.variables{}
объект переменных nginx, только чтение
s.OK
код OK
s.DECLINED
код DECLINED
s.AGAIN
код AGAIN
s.ERROR
код ERROR
s.ABORT
код ABORT
s.log(строка)
записывает отправленную строку в лог-файл ошибок на уровне лога info
s.warn(строка)
записывает отправленную строку в лог-файл ошибок на уровне лога warning
s.error(строка)
записывает отправленную строку в лог-файл ошибок на уровне лога error

Примеры

Декодирование URL

js_include urldecode.js;

js_set $decoded_foo decoded_foo;

Файл urldecode.js:

function decoded_foo(r) {
    return decodeURIComponent(r.args.foo);
}

Кодирование URL

js_include urlencode.js;

js_set $encoded_foo encoded_foo;
...

location / {
    proxy_pass http://example.com?foo=$encoded_foo;
}

Файл urlencode.js:

function encoded_foo(r) {
    return encodeURIComponent('foo & bar?');
}

Возврат самого быстрого ответа от прокси

js_include fastresponse.js;

location /start {
    js_content content;
}

location /foo {
    proxy_pass http://backend1;
}

location /bar {
    proxy_pass http://backend2;
}

Файл fastresponse.js:

function content(r) {
    var n = 0;

    function done(res) {
        if (n++ == 0) {
            r.return(res.status, res.responseBody);
        }
    }

    r.subrequest('/foo', r.variables.args, done);
    r.subrequest('/bar', r.variables.args, done);TBD
}

Создание HS JWT

js_include hs_jwt.js;

js_set $jwt jwt;

Файл hs_jwt.js:

function create_hs256_jwt(claims, key, valid) {
    var header = { "typ" : "JWT", "alg" : "HS256", "exp" : Date.now() + valid };

    var s = JSON.stringify(header).toBytes().toString('base64url') + '.'
            + JSON.stringify(claims).toBytes().toString('base64url');

    var h = require('crypto').createHmac('sha256', key);

    return s + '.' + h.update(s).digest().toString('base64url');
}

function jwt(r) {
    var claims = {
        "iss" : "nginx",
        "sub" : "alice",
        "foo" : 123,
        "bar" : "qq",
        "zyx" : false
    };

    return create_hs256_jwt(claims, 'foo', 600);
}

Доступ к API при помощи подзапроса

js_include subrequest.js;

keyval_zone zone=foo:10m;
...

location /keyval {
    js_content set_keyval;
}

location /version {
    js_content version;
}

location /api {
    api write=on;
}

Файл subrequest.js:

function set_keyval(r) {
    r.subrequest('/api/3/http/keyvals/foo',
        { method: 'POST',
          body: JSON.stringify({ foo: 789, bar: "ss dd 00" })},

        function(res) {
            if (res.status >= 300) {
                r.return(res.status, res.responseBody);
                return;
            }
            r.return(500);
        });
}

function version(r) {
    r.subrequest('/api/3/nginx', { method: 'GET' }, function(res) {
        if (res.status != 200) {
            r.return(res.status);
            return;
        }

        var json = JSON.parse(res.responseBody);
        r.return(200, json.version);
    });
}

Создание хэша secure_link

js_include hash.js;

js_set $new_foo create_secure_link;
...

location / {
    secure_link $cookie_foo;
    secure_link_md5 "$uri mykey";
    ...
}

location @login {
    add_header Set-Cookie "foo=$new_foo; Max-Age=60";
    return 302 /;
}

Файл hash.js:

function create_secure_link(r) {
    return require('crypto').createHash('md5')
                            .update(r.uri).update(" mykey")
                            .digest('base64url');
}