Spec-Zone.ru › nginx

Нативные модули

  • Обзор
  • Когда использовать нативные модули
  • Загрузка нативных модулей в NGINX
  • Сборка нативных модулей
  • Дополнительные ресурсы

Обзор

Нативные модули позволяют загружать в NGINX JavaScript разделяемые библиотеки на основе C (файлы .so) для выполнения критически важных с точки зрения производительности операций или интеграции на системном уровне. Эта возможность доступна только в движке QuickJS и не поддерживается нативным движком njs. Поддержка нативных модулей доступна начиная с версии 0.9.5.

Когда использовать нативные модули

Нативные модули полезны в следующих случаях:

  • Операции, критичные к производительности и выходящие за пределы возможностей JavaScript
  • Интеграция на системном уровне, требующая библиотек C
  • Использование существующих кодовых баз на C/C++

Нативные модули следует использовать для низкоуровневых примитивов, а не для сложной бизнес-логики, например для криптографических операций (хеширования, шифрования), сжатия и распаковки данных, разбора двоичных протоколов, высокопроизводительных операций со строками или математических вычислений. Сложная логика приложения должна оставаться в JavaScript, где её проще сопровождать, отлаживать и изменять.

Ограничения:

  • Нативные модули необходимо компилировать для той же архитектуры, что и NGINX
  • Нативные модули выполняются с полными привилегиями процесса и требуют тщательной проверки безопасности

Загрузка нативных модулей в NGINX

Нативные модули загружаются с помощью следующих директив, указанных в контексте main:

  • js_load_http_native_module для контекста HTTP
  • js_load_stream_native_module для контекста Stream

Пример конфигурации:

js_load_http_native_module /path/to/mylib.so;
js_load_http_native_module /path/to/other.so as myalias;

http {
    js_import main.js;

    server {
        listen 8000;
        location / {
            js_content main.handler;
        }
    }
}

После загрузки модуль можно импортировать в код JavaScript:

// Import by filename
import * as mylib from 'mylib.so';

// Import by alias
import * as myalias from 'myalias';

function handler(r) {
    let result = mylib.add(5, 10);
    r.return(200, `Result: ${result}\n`);
}

export default { handler };

Сборка нативных модулей

Нативные модули должны реализовывать функцию js_init_module в качестве точки входа. Эта функция вызывается QuickJS при загрузке модуля.

Полный пример простого нативного модуля, экспортирующего две функции:

#include <quickjs.h>

#define countof(x) (sizeof(x) / sizeof((x)[0]))

/* Add two numbers */
static JSValue
js_add(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
    int a, b;

    if (argc < 2) {
        return JS_ThrowTypeError(ctx, "expected 2 arguments");
    }

    if (JS_ToInt32(ctx, &a, argv[0]) < 0) {
        return JS_EXCEPTION;
    }

    if (JS_ToInt32(ctx, &b, argv[1]) < 0) {
        return JS_EXCEPTION;
    }

    return JS_NewInt32(ctx, a + b);
}

/* Reverse a string */
static JSValue
js_reverse_string(JSContext *ctx, JSValueConst this_val, int argc,
    JSValueConst *argv)
{
    char        *reversed;
    size_t       i, len;
    JSValue      result;
    const char  *str;

    if (argc < 1) {
        return JS_ThrowTypeError(ctx, "expected 1 argument");
    }

    str = JS_ToCStringLen(ctx, &len, argv[0]);
    if (!str) {
        return JS_EXCEPTION;
    }

    reversed = js_malloc(ctx, len + 1);
    if (!reversed) {
        JS_FreeCString(ctx, str);
        return JS_EXCEPTION;
    }

    for (i = 0; i < len; i++) {
        reversed[i] = str[len - 1 - i];
    }
    reversed[len] = '\0';

    result = JS_NewString(ctx, reversed);

    js_free(ctx, reversed);
    JS_FreeCString(ctx, str);

    return result;
}

/* Module function list */
static const JSCFunctionListEntry js_module_funcs[] = {
    JS_CFUNC_DEF("add", 2, js_add),
    JS_CFUNC_DEF("reverseString", 1, js_reverse_string),
};

/* Module initialization */
static int
js_module_init(JSContext *ctx, JSModuleDef *m)
{
    return JS_SetModuleExportList(ctx, m, js_module_funcs,
                                  countof(js_module_funcs));
}

/* Required entry point */
JSModuleDef *
js_init_module(JSContext *ctx, const char *module_name)
{
    JSModuleDef  *m;

    m = JS_NewCModule(ctx, module_name, js_module_init);
    if (!m) {
        return NULL;
    }

    JS_AddModuleExportList(ctx, m, js_module_funcs,
                           countof(js_module_funcs));

    return m;
}

Чтобы скомпилировать нативный модуль:

gcc -fPIC -shared -I/path/to/quickjs -o mymodule.so mymodule.c

где /path/to/quickjs — каталог, содержащий заголовочные файлы QuickJS.

Для корректного отслеживания памяти всегда используйте функции выделения памяти QuickJS (js_malloc, js_free) вместо функций стандартной библиотеки (malloc, free).

Дополнительные ресурсы

Дополнительные сведения о C API QuickJS:

  • Официальный сайт QuickJS
  • Заголовочный файл QuickJS (quickjs.h) содержит подробную документацию по API

© 2002-2021 Igor Sysoev
© 2011-2026 Nginx, Inc.
Licensed under the BSD License.
https://nginx.org/en/docs/njs/native_modules.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API