Appearance
原生模块
提示
来自deepseek解释
原文链接:https://nginx.org/en/docs/njs/native_modules.html
概述
原生模块允许将基于 C 的共享库(.so 文件)加载到 NGINX JavaScript 中,用于执行性能关键型操作或系统级集成。此功能仅在 QuickJS 引擎中可用,njs 原生引擎不支持该功能。原生模块支持自 0.9.5 版本起提供。
何时使用原生模块
原生模块在以下场景中非常有用:
- 超出 JavaScript 能力的性能关键型操作
- 需要 C 库的系统级集成
- 利用现有的 C/C++ 代码库
原生模块应用于底层原语,而非复杂的业务逻辑,例如:
- 加密操作(哈希、加密)
- 数据压缩/解压缩
- 二进制协议解析
- 高性能字符串操作
- 数学计算
复杂的应用逻辑应保留在 JavaScript 中,这样更易于维护、调试和修改。
限制:
- 原生模块必须为与 NGINX 相同的架构编译
- 原生模块以完整的进程权限运行,需要仔细进行安全审查
在 NGINX 中加载原生模块
原生模块使用以下指令在主配置上下文中加载:
配置示例:
nginx
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 代码中导入该模块:
js
// 按文件名导入
import * as mylib from 'mylib.so';
// 按别名导入
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 加载模块时被调用。
以下是一个导出两个函数的简单原生模块完整示例:
c
#include <quickjs.h>
#define countof(x) (sizeof(x) / sizeof((x)[0]))
/* 两数相加 */
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);
}
/* 反转字符串 */
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;
}
/* 模块函数列表 */
static const JSCFunctionListEntry js_module_funcs[] = {
JS_CFUNC_DEF("add", 2, js_add),
JS_CFUNC_DEF("reverseString", 1, js_reverse_string),
};
/* 模块初始化 */
static int js_module_init(JSContext *ctx, JSModuleDef *m)
{
return JS_SetModuleExportList(ctx, m, js_module_funcs,
countof(js_module_funcs));
}
/* 必需的入口点 */
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;
}编译原生模块:
bash
gcc -fPIC -shared -I/path/to/quickjs -o mymodule.so mymodule.c其中 /path/to/quickjs 是包含 QuickJS 头文件的目录。
为确保正确的内存跟踪,请始终使用 QuickJS 内存分配函数(js_malloc、js_free),而非标准库函数(malloc、free)。
更多资源
有关 QuickJS C API 的更多信息:
- QuickJS 官方网站
- QuickJS 头文件(quickjs.h)包含全面的 API 文档