Nginx 启用 NJS 与 QuickJS 支持

前言

大概两年前,Nginx 官方发布了 NJS module,让我们可以在 Nginx 中直接使用 JavaScript 来做扩展。当时的 NJS 仅支持 ES5 和部分 ES6 语法,算是一次比较早期的尝试。那时候,各种博客充满着"JS 的风终究吹到了 Nginx"。但说实话,那个时候我没有找到特别适合的应用场景,加上部署和语法上的限制,兴趣并不大,于是搁置了。

直到最近,Nginx 博客宣布:Nginx 的 JS 引擎支持切换到 QuickJS 。这让我眼前一亮------QuickJS 以小巧、轻量、支持完整 ES6 语法闻名,性能不俗、内存占用低,而且支持较多新特性。我一直对它有兴趣,但苦于没有合适的使用场景。而这次 Nginx + QuickJS 的结合,让我有了一个理由来试一试。

安装 NJS module

注意:

编译 NJS 模块时,需要先下载与你当前运行版本一致的 Nginx 源码,否则会因为版本不匹配导致编译失败。

官方下载地址:nginx.org/en/download...

首先,将 NJS 源码克隆到本地:

bash 复制代码
git clone https://github.com/nginx/njs

进入 Nginx 源码目录,使用 --add-dynamic-module 配置参数添加 NJS 模块:

bash 复制代码
./configure --add-dynamic-module=<path-to-njs>/nginx

编译完成后,生成的 .so 模块文件会放在 <nginx-source-path>/objs 目录中。

nginx.conf 中导入模块(注意替换路径):

nginx 复制代码
load_module <nginx-source-path>/objs/ngx_http_js_module.so;

Hello World 示例

首先,新建一个 http.js 文件:

js 复制代码
function hello(r) {
    r.headersOut['Content-Type'] = 'text/html';
    r.return(200, `
<!DOCTYPE html>
<html>
<head>
    <title>Hello World</title>
    <style>
        body {
            text-align: center;
            margin-top: 100px;
        }
        h1 {
            color: #2c3e50;
        }
    </style>
</head>
<body>
    <h1>Hello World from njs!</h1>
    <p>This page was generated by Nginx JavaScript module</p>
</body>
</html>
    `);
}

export default { hello };

然后在 nginx.conf 中配置 NJS 支持:

nginx 复制代码
load_module /usr/lib/nginx/modules/ngx_http_js_module.so;

worker_processes  1;
events {
    worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;

  server {
    listen 8000;

    js_import http from /etc/nginx/js/http.js;
    location / {
      add_header Content-Type text/html;
      js_content http.hello;
    }
  }
}

启动 Nginx 后,访问 http://127.0.0.1:8000,即可看到:

配置 QuickJS 支持

上面的例子只是启用了 NJS,如果想让 Nginx 使用 QuickJS 引擎,需要额外的编译步骤。

下载 QuickJS 源码

bash 复制代码
git clone https://github.com/bellard/quickjs

编译 QuickJS

进入 QuickJS 源码目录,执行:

bash 复制代码
CFLAGS='-fPIC' make libquickjs.a

重新编译 Nginx 模块

进入 Nginx 源码根目录,配置编译参数,额外添加 --with-cc-opt(头文件路径)和 --with-ld-opt(库路径):

bash 复制代码
./configure --add-dynamic-module=<path-to-njs>/nginx \
    --with-cc-opt="-I <path-to-quickjs>" \
    --with-ld-opt="-L <path-to-quickjs>"

编译完成后,和 NJS 一样在 nginx.conf 中加载 .so 模块即可。

QuickJS 示例

下面是官方的示例,充分展示了 QuickJS 对 ES6+ 语法的完整支持,包括 generator、BigInt、解构赋值等:

js 复制代码
// js/analytics.js
class RequestAnalytics {
    *getHeaderMetrics(headers) {
        for (const [key, value] of Object.entries(headers)) {
            yield {
                header: key.toLowerCase(),
                size: key.length + value.length,
                type: key.startsWith('x-') ? 'custom' : 'standard'
            };
        }
    }

    processRequest(r) {
        const {
            method = 'GET',
            uri = '/',
            httpVersion = '1.0'
        } = r;

        const headerStats = [];
        for (const metric of this.getHeaderMetrics(r.headersIn)) {
            headerStats.push(metric);
        }

        const timestamp = BigInt(Date.now());
        const headerCount = headerStats.length;
        const customHeaders = headerStats.filter(({ type }) => type === 'custom').length;

        r.return(200, JSON.stringify({
            message: `Request processed at ${timestamp}`,
            stats: { headerCount, customHeaders },
            serverInfo: `${method} ${uri} HTTP/${httpVersion}`
        }, null, 2));
    }
}

const analytics = new RequestAnalytics();
export default { processRequest: (r) => analytics.processRequest(r) };

配置 nginx.conf,唯一的区别是需要指定 js_engine qjs,否则默认会使用 NJS 引擎:

nginx 复制代码
load_module /usr/lib/nginx/modules/ngx_http_js_module.so;

worker_processes  1;
events {
    worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;
  
  server {
    listen 8001;

    js_engine qjs;
    js_import analytics from /etc/nginx/js/analytics.js;

    location / {
        add_header Content-Type application/json;
        js_content analytics.processRequest;
    }    
  }
}

启动 Nginx 后访问 http://127.0.0.1:8001,返回 JSON 数据:

结语

本篇我们完成了 Nginx 启用 NJS + QuickJS 的安装、编译和示例运行。

相比传统 Nginx 配置,加入 JS 引擎的好处是显而易见的------你可以在配置中直接写复杂的逻辑,而不必依赖额外的后端服务。

有了 Nginx + JS,我们可以做更多事情,例如:

  • 多条件的复杂路由判断
  • 动态请求签名和鉴权
  • 请求体解析与数据提取
  • 与外部 API 通信
  • Web 应用防火墙(WAF)逻辑实现
  • 自定义响应处理与 A/B 测试

下一篇,我会带来一组更实用的 Nginx + QuickJS 场景 Demo,来演示他的使用场景和使用示例。

相关链接

相关推荐
skeletron20118 分钟前
🚀AI评测这么玩(2)——使用开源评测引擎eval-engine实现问答相似度评估
前端·后端
前端开发爱好者8 分钟前
Vite 7.1.1 疑似遭受大规模 "攻击"!
前端·vue.js·vite
小徐_233311 分钟前
uni-app 还在手写请求?alova 帮你全搞定!
前端·uni-app·axios
shark_chili19 分钟前
颠覆认知!这才是synchronized最硬核的打开方式
后端
七十二時_阿川22 分钟前
React 浏览器重新绘制之前副作用之useLayoutEffect
前端·程序员
就是帅我不改22 分钟前
99%的Java程序员都写错了!高并发下你的Service层正在拖垮整个系统!
后端·架构
Apifox23 分钟前
API 文档中有多种参数结构怎么办?Apifox 里用 oneOf/anyOf/allOf 这样写
前端·后端·测试
似水流年流不尽思念23 分钟前
如何实现一个线程安全的单例模式?
后端·面试
楽码26 分钟前
了解HMAC及实现步骤
后端·算法·微服务
IT小番茄28 分钟前
若依框架导出 Excel 签名实现方案
前端·后端