JavaScript
nginx

nginScriptで遊んでみた

More than 3 years have passed since last update.

nginxをJavaScriptで拡張できるnginScriptがローンチされたので軽く触ってみた。

https://www.nginx.com/blog/launching-nginscript-and-looking-ahead/


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_luamruby_setと違ってhttpコンテキストでしか使えないので注意。(serverlocationコンテキストでは利用不可)

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にはrewriteaccesscontentlogなどなどたくさんの実行フェーズがあってngx_luangx_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-TypeContent-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という感じですが、リリースされたばかりですし、今後に期待ですね。