モジュール ngx_http_js_module

設定例
ディレクティブ
     js_body_filter
     js_content
     js_context_reuse
     js_engine
     js_fetch_buffer_size
     js_fetch_ciphers
     js_fetch_max_response_buffer_size
     js_fetch_protocols
     js_fetch_timeout
     js_fetch_trusted_certificate
     js_fetch_verify
     js_fetch_verify_depth
     js_header_filter
     js_import
     js_include
     js_path
     js_periodic
     js_preload_object
     js_set
     js_shared_dict_zone
     js_var
リクエスト引数

ngx_http_js_module モジュールは、JavaScript言語のサブセットであるnjsで、ロケーションハンドラーと変数ハンドラーを実装するために使用されます。

ダウンロードとインストールの手順はこちらにあります。

設定例

この例は0.4.0以降で動作します。

http {
    js_import http.js;

    js_set $foo     http.foo;
    js_set $summary http.summary;
    js_set $hash    http.hash;

    resolver 10.0.0.1;

    server {
        listen 8000;

        location / {
            add_header X-Foo $foo;
            js_content http.baz;
        }

        location = /summary {
            return 200 $summary;
        }

        location = /hello {
            js_content http.hello;
        }

        # since 0.7.0
        location = /fetch {
            js_content                   http.fetch;
            js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
        }

        # since 0.7.0
        location = /crypto {
            add_header Hash $hash;
            return     200;
        }
    }
}

http.jsファイル

function foo(r) {
    r.log("hello from foo() handler");
    return "foo";
}

function summary(r) {
    var a, s, h;

    s = "JS summary\n\n";

    s += "Method: " + r.method + "\n";
    s += "HTTP version: " + r.httpVersion + "\n";
    s += "Host: " + r.headersIn.host + "\n";
    s += "Remote Address: " + r.remoteAddress + "\n";
    s += "URI: " + r.uri + "\n";

    s += "Headers:\n";
    for (h in r.headersIn) {
        s += "  header '" + h + "' is '" + r.headersIn[h] + "'\n";
    }

    s += "Args:\n";
    for (a in r.args) {
        s += "  arg '" + a + "' is '" + r.args[a] + "'\n";
    }

    return s;
}

function baz(r) {
    r.status = 200;
    r.headersOut.foo = 1234;
    r.headersOut['Content-Type'] = "text/plain; charset=utf-8";
    r.headersOut['Content-Length'] = 15;
    r.sendHeader();
    r.send("nginx");
    r.send("java");
    r.send("script");

    r.finish();
}

function hello(r) {
    r.return(200, "Hello world!");
}

// since 0.7.0
async function fetch(r) {
    let results = await Promise.all([ngx.fetch('https://nginx.dokyumento.jp/'),
                                     ngx.fetch('https://nginx.dokyumento.jp/en/')]);

    r.return(200, JSON.stringify(results, undefined, 4));
}

// since 0.7.0
async function hash(r) {
    let hash = await crypto.subtle.digest('SHA-512', r.headersIn.host);
    r.setReturnValue(Buffer.from(hash).toString('hex'));
}

export default {foo, summary, baz, hello, fetch, hash};

ディレクティブ

構文 js_body_filter function | module.function [buffer_type=string | buffer];
デフォルト
コンテキスト location, if in location, limit_except

このディレクティブはバージョン0.5.2で登場しました。

njs関数をレスポンスボディフィルターとして設定します。フィルター関数は、レスポンスボディの各データチャンクに対して、次の引数とともに呼び出されます。

r
HTTPリクエストオブジェクト
data
入力データチャンク。buffer_typeの値に応じて、文字列またはBufferになります。デフォルトは文字列です。0.8.5以降、dataの値はデフォルトで有効なUTF-8文字列に暗黙的に変換されます。バイナリデータの場合は、buffer_typeの値をbufferに設定する必要があります。
flags
次のプロパティを持つオブジェクト
last
データが最後のバッファの場合はtrueとなるブール値。

フィルター関数は、r.sendBuffer()を呼び出すことで、入力データチャンクの変更されたバージョンを次のボディフィルターに渡すことができます。たとえば、レスポンスボディのすべての小文字を変換するには、

function filter(r, data, flags) {
    r.sendBuffer(data.toLowerCase(), flags);
}

フィルタリングを停止する場合(以降のデータチャンクはjs_body_filterを呼び出さずにクライアントに渡されます)、r.done()を使用できます。

フィルター関数がレスポンスボディの長さを変更する場合、チャンク転送エンコーディングを強制するために、js_header_filterで「Content-Length」レスポンスヘッダー(存在する場合)をクリアする必要があります。

js_body_filterハンドラーは結果をすぐに返すため、同期操作のみをサポートします。したがって、r.subrequest()setTimeout()などの非同期操作はサポートされていません。

このディレクティブは、ifブロック内で0.7.7以降に指定できます。

構文 js_content function | module.function;
デフォルト
コンテキスト location, if in location, limit_except

njs関数をロケーションコンテンツハンドラーとして設定します。0.4.0以降、モジュール関数を参照できます。

このディレクティブは、ifブロック内で0.7.7以降に指定できます。

構文 js_context_reuse number;
デフォルト
js_context_reuse 128;
コンテキスト http, server, location

このディレクティブはバージョン0.8.6で登場しました。

QuickJSエンジンで再利用されるJSコンテキストの最大数を設定します。各コンテキストは、単一のリクエストに使用されます。完了したコンテキストは、再利用可能なコンテキストのプールに入れられます。プールがいっぱいの場合は、コンテキストが破棄されます。

構文 js_engine njs | qjs;
デフォルト
js_engine njs;
コンテキスト http, server, location

このディレクティブはバージョン0.8.6で登場しました。

njsスクリプトに使用されるJavaScriptエンジンを設定します。njsパラメータはnjsエンジンを設定します。これはデフォルトでも使用されます。qjsパラメータはQuickJSエンジンを設定します。

構文 js_fetch_buffer_size size;
デフォルト
js_fetch_buffer_size 16k;
コンテキスト http, server, location

このディレクティブはバージョン0.7.4で登場しました。

Fetch APIでの読み書きに使用するバッファのsizeを設定します。

構文 js_fetch_ciphers ciphers;
デフォルト
js_fetch_ciphers HIGH:!aNULL:!MD5;
コンテキスト http, server, location

このディレクティブはバージョン0.7.0で登場しました。

Fetch APIを使用したHTTPSリクエストで有効な暗号を指定します。暗号はOpenSSLライブラリで理解される形式で指定されます。

完全なリストは、「openssl ciphers」コマンドを使用して表示できます。

構文 js_fetch_max_response_buffer_size size;
デフォルト
js_fetch_max_response_buffer_size 1m;
コンテキスト http, server, location

このディレクティブはバージョン0.7.4で登場しました。

Fetch APIで受信したレスポンスの最大sizeを設定します。

構文 js_fetch_protocols [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];
デフォルト
js_fetch_protocols TLSv1 TLSv1.1 TLSv1.2;
コンテキスト http, server, location

このディレクティブはバージョン0.7.0で登場しました。

Fetch APIを使用したHTTPSリクエストで指定されたプロトコルを有効にします。

構文 js_fetch_timeout time;
デフォルト
js_fetch_timeout 60s;
コンテキスト http, server, location

このディレクティブはバージョン0.7.4で登場しました。

Fetch APIの読み書きのタイムアウトを定義します。タイムアウトは、応答全体ではなく、連続する2つの読み取り/書き込み操作の間でのみ設定されます。この時間内にデータが送信されない場合、接続は閉じられます。

構文 js_fetch_trusted_certificate file;
デフォルト
コンテキスト http, server, location

このディレクティブはバージョン0.7.0で登場しました。

Fetch APIでHTTPS証明書を検証するために使用される、PEM形式の信頼できるCA証明書を含むfileを指定します。

構文 js_fetch_verify on | off;
デフォルト
js_fetch_verify on;
コンテキスト http, server, location

このディレクティブはバージョン0.7.4で登場しました。

Fetch APIを使用して、HTTPSサーバー証明書の検証を有効または無効にします。

構文 js_fetch_verify_depth number;
デフォルト
js_fetch_verify_depth 100;
コンテキスト http, server, location

このディレクティブはバージョン0.7.0で登場しました。

Fetch APIを使用したHTTPSサーバー証明書チェーンの検証深度を設定します。

構文 js_header_filter function | module.function;
デフォルト
コンテキスト location, if in location, limit_except

このディレクティブはバージョン0.5.1で登場しました。

njs関数をレスポンスヘッダーフィルターとして設定します。このディレクティブを使用すると、レスポンスヘッダーの任意のヘッダーフィールドを変更できます。

js_header_filterハンドラーは結果をすぐに返すため、同期操作のみをサポートします。したがって、r.subrequest()setTimeout()などの非同期操作はサポートされていません。

このディレクティブは、ifブロック内で0.7.7以降に指定できます。

構文 js_import module.js | export_name from module.js;
デフォルト
コンテキスト http, server, location

このディレクティブはバージョン0.4.0で登場しました。

njsでロケーションハンドラーと変数ハンドラーを実装するモジュールをインポートします。export_nameは、モジュール関数にアクセスするための名前空間として使用されます。export_nameが指定されていない場合は、モジュール名が名前空間として使用されます。

js_import http.js;

ここでは、モジュール名httpがエクスポートへのアクセス時の名前空間として使用されます。インポートされたモジュールがfoo()をエクスポートする場合、http.fooを使用して参照します。

複数のjs_importディレクティブを指定できます。

このディレクティブは、0.7.7以降、serverおよびlocationレベルで指定できます。

構文 js_include file;
デフォルト
コンテキスト http

njsでロケーションハンドラーと変数ハンドラーを実装するファイルを指定します。

nginx.conf:
js_include http.js;
location   /version {
    js_content version;
}

http.js:
function version(r) {
    r.return(200, njs.version);
}

このディレクティブは0.4.0で廃止され、0.7.1で削除されました。代わりにjs_importディレクティブを使用する必要があります。

構文 js_path path;
デフォルト
コンテキスト http, server, location

このディレクティブはバージョン0.3.0で登場しました。

njsモジュールの追加パスを設定します。

このディレクティブは、0.7.7以降、serverおよびlocationレベルで指定できます。

構文 js_periodic function | module.function [interval=time] [jitter=number] [worker_affinity=mask];
デフォルト
コンテキスト location

このディレクティブはバージョン0.8.1で登場しました。

定期的に実行するコンテンツハンドラーを指定します。ハンドラーは、最初の引数としてセッションオブジェクトを受け取り、ngxなどのグローバルオブジェクトにもアクセスできます。

オプションのintervalパラメータは、2回の連続実行の間隔を設定します。デフォルトは5秒です。

オプションのjitterパラメータは、ロケーションコンテンツハンドラーがランダムに遅延する時間を設定します。デフォルトでは、遅延はありません。

デフォルトでは、js_handlerはワーカープロセス0で実行されます。オプションのworker_affinityパラメータを使用すると、ロケーションコンテンツハンドラーを実行する必要がある特定のワーカープロセスを指定できます。各ワーカープロセスセットは、許可されたワーカープロセスのビットマスクで表されます。allマスクを使用すると、すべてのワーカープロセスでハンドラーを実行できます。

example.conf:

location @periodics {
    # to be run at 1 minute intervals in worker process 0
    js_periodic main.handler interval=60s;

    # to be run at 1 minute intervals in all worker processes
    js_periodic main.handler interval=60s worker_affinity=all;

    # to be run at 1 minute intervals in worker processes 1 and 3
    js_periodic main.handler interval=60s worker_affinity=0101;

    resolver 10.0.0.1;
    js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}

example.js:

async function handler(s) {
    let reply = await ngx.fetch('https://nginx.dokyumento.jp/en/docs/njs/');
    let body = await reply.text();

    ngx.log(ngx.INFO, body);
}

構文 js_preload_object name.json | name from file.json;
デフォルト
コンテキスト http, server, location

このディレクティブはバージョン0.7.8で登場しました。

設定時にイミュータブルオブジェクトをプリロードします。nameは、njsコードでオブジェクトを使用できるグローバル変数の名前として使用されます。nameが指定されていない場合は、代わりにファイル名が使用されます。

js_preload_object map.json;

ここでは、mapがプリロードされたオブジェクトにアクセスする際の名前として使用されます。

複数のjs_preload_objectディレクティブを指定できます。

構文 js_set $variable function | module.function [nocache];
デフォルト
コンテキスト http, server, location

指定されたvariableにnjs functionを設定します。0.4.0以降、モジュール関数を参照できます。

この関数は、指定されたリクエストで変数が最初に参照されたときに呼び出されます。正確なタイミングは、変数が参照されるフェーズによって異なります。これを使用して、変数評価に関係のないロジックを実行できます。たとえば、変数がlog_formatディレクティブでのみ参照される場合、そのハンドラーはログフェーズまで実行されません。このハンドラーは、リクエストが解放される直前にクリーンアップを実行するために使用できます。

0.8.6以降、オプションの引数nocacheが指定されている場合、ハンドラーは参照されるたびに呼び出されます。rewriteモジュールの現在の制限により、nocache変数がsetディレクティブによって参照される場合、そのハンドラーは常に固定長の値を返す必要があります。

js_setハンドラーは結果をすぐに返すため、同期操作のみをサポートします。したがって、r.subrequest()setTimeout()などの非同期操作はサポートされていません。

このディレクティブは、0.7.7以降、serverおよびlocationレベルで指定できます。

構文 js_shared_dict_zone zone=name:size [timeout=time] [type=string|number] [evict];
デフォルト
コンテキスト http

このディレクティブはバージョン0.8.0で登場しました。

ワーカープロセス間で共有されるキーと値の辞書を保持する共有メモリ領域のnamesizeを設定します。

デフォルトでは、共有辞書はキーと値に文字列を使用します。オプションのtypeパラメーターを使用すると、値の型を数値に再定義できます。

オプションのtimeoutパラメーターは、共有辞書のエントリがすべてゾーンから削除されるまでの時間(ミリ秒単位)を設定します。一部のエントリに異なる削除時間が必要な場合は、addincr、およびsetメソッドのtimeout引数で設定できます(0.8.5)。

オプションのevictパラメーターは、ゾーンストレージが枯渇したときに、最も古いキーと値のペアを削除します。

example.conf:
    # Creates a 1Mb dictionary with string values,
    # removes key-value pairs after 60 seconds of inactivity:
    js_shared_dict_zone zone=foo:1M timeout=60s;

    # Creates a 512Kb dictionary with string values,
    # forcibly removes oldest key-value pairs when the zone is exhausted:
    js_shared_dict_zone zone=bar:512K timeout=30s evict;

    # Creates a 32Kb permanent dictionary with number values:
    js_shared_dict_zone zone=num:32k type=number;

example.js:
    function get(r) {
        r.return(200, ngx.shared.foo.get(r.args.key));
    }

    function set(r) {
        r.return(200, ngx.shared.foo.set(r.args.key, r.args.value));
    }

    function del(r) {
        r.return(200, ngx.shared.bar.delete(r.args.key));
    }

    function increment(r) {
        r.return(200, ngx.shared.num.incr(r.args.key, 2));
    }

構文 js_var $変数 [];
デフォルト
コンテキスト http, server, location

このディレクティブはバージョン0.5.3で登場しました。

書き込み可能な変数を宣言します。値には、テキスト、変数、およびそれらの組み合わせを含めることができます。この変数は、setディレクティブで作成された変数とは異なり、リダイレクト後も上書きされません。

このディレクティブは、0.7.7以降、serverおよびlocationレベルで指定できます。

リクエスト引数

各HTTP njsハンドラーは、リクエストオブジェクトという1つの引数を受け取ります。