nginxをJavaScriptで拡張できるnginScriptがローンチされたので軽く触ってみた。
nginScriptをビルド
nginScriptは今のところnginx本家のMercurialリポジトリからcloneすることができる。また、nginxモジュールの実装とnginScriptの実装が一緒に含まれているため、まずはnginScriptをビルドする。
hg clone http://hg.nginx.org/njs/
cd njs
./configure
make
nginxにnginScriptを組み込んでビルド
nginScriptのビルドが完了したら今度はnginx本体のビルドを行う。configure
実行時に--add-module
でさきほどビルドしたnginScript(njs
)のパスを指定してビルドする。
wget http://nginx.org/download/nginx-1.9.5.tar.gz
tar zxvf nginx-1.9.5.tar.gz
cd nginx-1.9.5
./configure --add-module=<path-to-njs>/nginx
make
sudo make install
js_setでJavaScriptの実行結果をnginxの変数に代入
js_set
はJavaScriptの実行結果をnginxの内部変数に代入する。set_by_lua
やmruby_set
と違ってhttp
コンテキストでしか使えないので注意。(server
、location
コンテキストでは利用不可)
http {
js_set $var "
var result = 'Hello, World\n';
result
";
server {
listen 8080;
location /js-var {
return 200 $var;
}
}
...
curl
で叩く。
$ curl -s http://127.0.0.1:8080/js-var
Hello, World
$
js_runでJavaScriptの実行する
js_run
は特定のlocation
に対してJavaScriptを実行するためのフックをかけることができる。$r
に内部データを突っ込んでるのがとてもPerlっぽい。
server {
listen 8080;
location /js-run {
js_run "
var res;
res = $r.response;
res.status = 200;
res.sendHeader();
res.send('Hello, World\n');
res.finish();
";
}
}
curl
で叩く。
$ curl -s http://127.0.0.1:8080/js-var
Hello, World
$
nginxにはrewrite
、access
、content
、log
などなどたくさんの実行フェーズがあってngx_luaやngx_mrubyだとそれぞれのフェーズにフックをかけてもっといろんなことができる(e.g. アップストリームにプロキシする直前にスクリプト実行してアクセス制御とか)のだが、nginScriptでは今のところフックをかけれるのはcontent
フェーズのみだ。
$rからnginxの内部にアクセス
$r
はJavaScriptでnginxの内部構造にアクセスするためのエンドポイントだ。今のところアクセスできるものは少ない。詳細はREADMEを見て欲しい。
server {
listen 8080;
location /js-r {
js_run "
var res;
res = $r.response;
res.status = 200;
res.sendHeader();
res.send($r.uri);
res.send('\n');
res.send($r.method);
res.send('\n');
res.send($r.remoteAddress);
res.send('\n');
res.finish();
";
}
}
curl
で叩く。
$ curl -s http://127.0.0.1:8080/js-r
/js-r
GET
127.0.0.1
$
レスポンスヘッダを操作
$r.response.headers
を利用するとレスポンスヘッダを操作することができる。
$r.response.headers.Bokko = 'cubicdaiya';
なお、HTTPのヘッダは-
で区切ることがよくあるが、以下のような書き方はSyntaxError
になる。
$r.response.headers.X-Bokko = 'cubicdaiya';
ヘッダ名に-
を含めたい場合は以下のように書く。
$r.response.headers['X-Bokko'] = 'cubicdaiya';
ところでngx_luaだと内部的に_
を-
に変換してくれてとてもかしこい。
-- ngx_lua
-- 内部的に「X-Bokko: cubicdaiya」に変換される
ngx.header.X_Bokko = 'cubicdaiya';
あと、nginxのレスポンスヘッダは連結リストで表現されているので操作にかかるコストはO(n)である。
また、Content-Type
とContent-Length
は専用のアクセサが用意されている。
$r.response.headers.contentType = 'text/plain';
$r.response.headers.contentLength = 15;
まとめ
今のところnginScriptでできるのは、
-
js_set
でJavaScriptの実行結果をnginxの変数に代入できる -
js_run
で特定のlocation
内でJavaScriptを実行できる -
$r
からnginxの内部構造にちょっとだけアクセスできる - レスポンスヘッダの操作ができる
といった感じです。まだ機能少なめでearly development phaseという感じですが、リリースされたばかりですし、今後に期待ですね。