w3ctech

nginxScript->诞生->现状->展望未来

nginxScript->诞生->现状->展望未来

在很长一段时间里,我一直在想(如何)赋予NGINX更多的脚本能力。脚本可以让人们在NGINX上做更多的事,(正因为如此)也就再也没有必要写C模块。举个例子来说,在处理NGINX方面,Lua是一个很好的工具,但是Lua不像其它语言一样被人所熟知。
JavaScript是一门最显著的语言。在过去的3年中,JavaScript一直是非常受欢迎的语言(#1 on GitHub)。JavaScript也非常适合作为我们配置NGINX的语言。
最近才刚刚宣布,我们可以将JavaScript虚拟机(VM)的工作原型植入NGINX里面。没过多久我们又要宣布,nginScript预览版将会在nginx.conf 2015上首次亮相。
在NGINX开源软件和NGINX Plus的发展历程中,nginScipt的发布无疑会是另一个里程碑。我想就这个机会来阐述一下什么是nginScript,然后描述为什么nginScript非常必要,接下来分享一些例子,最后畅想一下nginScript的未来。

nginScript为何物

nginScript完美重现JavaScript里面大部分内容,包括配置NGINX所需的功能。不支持JavaScript中(对配置NGINX来说)不是很有用的功能以及一些不相关的原生对象。
nginScript可以被用来快速解决问题,更方便地配置NGINX以及更有效地操纵NGINX。但是因为NGINX运行在应用的交付层面,所以出于长期稳定性,安全性,规模的考虑,需要你重构自己的应用。
nginScript分为两大部分:

  1. 常见的虚拟机(VM)以及字节码编译器(快速启动,销毁时间)。阻塞进程(可以作为另一种JavaScript阻塞进程的方式),例如HTTP子请求可以被挂起或者被中断。
  2. 在配置NGINX过程中,嵌入JavaScript代码块需要遵循(一定的)配置规则。这些代码块在运行时被执行,和HTTP事务运行机制类似。你可以创建功能强大的条件式配置项,快速修改请求和响应。可以针对(发送给NGINX的)每个请求,调整NGINX服务器的内部操作。

这里有一些当前比较流行的JavaScript虚拟机。但是只有通过浏览器才能使虚拟机性能达到最优。nginScript虚拟机专注于服务器的比较条件。我们可以为了每个请求运行独立的虚拟机,所以垃圾回收机制就没有必要啦。并且nginScript虚拟机可以预先载入,这样的话,NGINX代码可以运行起来。

nginScript成为可能的因素

nginScript具有广泛的潜在用途。现在下面列举的功能已经在nginScript上实现。在未来的一段时间这些功能将会被扩展:
抵御安全威胁 --nginScript可以通过限速的方式来对具有欺骗性的资源请求进行动态响应或者驳回请求。
通过流量获取灵活的控制 --使用请求中的信息或者其他资源,可以实现更灵活的流量路由控制。
跨应用时合并功能 --你可以将重复的功能移出应用,然后在应用发布平台中引入。
功能类库加速应用的发展 --nginScript代码可以被扩展,复用,改善,存储以及分享。

在未来,我们将在nginScript现有的基础上增加更多的功能,然后延长它的作用域,所以你可以是为了解决任务来使用,例如修正应用bug,改变业务规则,使我们的体验变得个性化以及跨服务器切分请求和聚合响应。

nginScript行为

在NGINX中插入JavaScript代码可以使用两种指令:js_set和js_run。

js_set

js_set指令通过JavaScript代码执行结果来设置变量的值:

http {
    js_set $hello_world "
            var str = 'Hello World!';
            // JavaScript
            str;
    ";

    server {
        ...
        location /{
            return 200 $hello_world;
        }
    }
}

在上面的例子中,$hello_world的值会被设置成JavaScript代码中最后一个语句的值。返回给客户端$hello_world变量的值为"hello world!"。

使用js_set方式设置变量可以使用在任何NGINX命令,作为变量参数,例如limit_req_zone, proxy_pass, and sub_filter。

js_run

js_run命令是在内容生成阶段执行的。被用来执行原生的JavaScript代码和生成HTTP响应。js_run命令写在location代码块中,然后在location匹配请求的URL时触发JavaScript代码的执行。

location / {
    js_run "
        var res;
        res = $r.response;
        res.status = 200;
        res.send('Hello World!');
        res.finish();
    ";
}

请求参数

由于nginScript,你可以获取请求参数(通过$r变量)。下面的例子将请求参数返回给请求。

http {
    js_set $summary "
    var a, s, h;

    s = 'JS 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 8000;

        location /summary {
            return 200 $summary;
        }
    }
}

常见的请求路由

通过NGINX中的location代码块,你可以基于URI进行路由控制。通过nginScript你可以基于请求中的任何数据来进行路由控制,包括cookies,headers,arguments甚至是请求主体中的任何关键字。下面的例子展示的是路由控制是通过被命名为upstream的argument所呈现的:

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;
        }
    }
}

nginScript的未来

我们的目标是将NGINX打造成connective tissue以及成为现代web应用的流量管理层的核心。在NGINX中嵌入JavaScript代码是在这个方向迈出的重要一步。nginScript融入Lua,Perl以及以可靠方式扩展NGINX的模块。
nginScript不是用来取代Lua或者其它的嵌入语言。JavaScript已经被添加到用于NGINX扩展的社区中,然后我们希望在未来这个数字还可以继续增长。
nginScript已经可以进行测试,原型测试,功能化,修正安全问题以及策略性的进行应用升级和调度。当你在测试nginScript以及考虑nginScript在你的应用发展和交付策略中的长远地位时,我们期待您的发聩。

w3ctech微信

扫码关注w3ctech微信公众号

共收到4条回复