Nginx的javascript module中是否可以实现数据持久化?
Nginx JavaScript模块(njs)数据持久化方案说明
njs本身没有内置开箱即用的跨请求持久化存储能力,但可以通过以下几种官方支持的方式实现数据存储,满足你提取请求数据、校验后续访问的需求:
方案1:使用共享内存字典(内存级持久化)
这是njs原生支持的跨请求共享存储方案,数据存放在Nginx的共享内存区域,所有worker进程都可以读写,配置和使用成本最低:
- 首先在Nginx配置中声明共享内存块:
js_shared_dict request_store 10m; # 分配10M共享内存,存储名称为request_store
- 在njs代码中直接调用API读写:
const reqStore = ngx.shared.request_store; // 存储数据,第三个参数为过期时间,单位为秒,示例为1小时有效期 reqStore.set('user_123_access_token', 'xxx', 3600); // 读取数据做校验 const token = reqStore.get('user_123_access_token'); if (token !== expectedToken) { return ngx.exit(403); }
注意:该方案的数据会在Nginx重启、重载后丢失,适合存储临时校验凭证、短周期访问统计等不需要永久留存的数据。
方案2:本地文件持久化
njs支持原生文件读写能力,可以把数据持久化到服务器本地磁盘,服务重启也不会丢失:
- 示例代码:
const fs = require('fs'); // 存储请求提取的数据 const requestRecord = { uid: '123', accessSign: 'xxx', expireAt: Date.now() + 3600 * 1000 }; fs.writeFileSync('/var/lib/nginx/njs_store/access_record.json', JSON.stringify(requestRecord)); // 读取校验 const savedRecord = JSON.parse(fs.readFileSync('/var/lib/nginx/njs_store/access_record.json')); if (Date.now() > savedRecord.expireAt || savedRecord.accessSign !== currentSign) { return ngx.exit(403); }
注意:需要提前给Nginx运行用户开放存储目录的读写权限,同时要处理好多请求并发写入的冲突问题,避免文件内容损坏。
方案3:对接外部存储
如果需要跨Nginx实例共享数据、或者需要高可靠持久化,可以通过njs的ngx.fetch接口对接Redis、MySQL等外部存储,或者直接调用业务后端的校验接口:
- 示例代码(调用内部校验接口):
async function checkAccess(r) { const sign = r.headers['X-Access-Sign']; const resp = await ngx.fetch('http://127.0.0.1:8080/api/check_sign', { method: 'POST', body: JSON.stringify({sign: sign}) }); const result = await resp.json(); if (!result.allow) { return r.return(403); } r.return(200); }
注意:需要给外部调用配置合理的超时时间,避免外部存储故障导致Nginx请求阻塞。
内容的提问来源于stack exchange,提问作者Oliver Stahl
相关产品推荐
相关产品推荐

