Nginx - 整合lua 实现对POST请求的参数拦截校验(不使用Openresty)
文章目录
- 概述
- 步骤 1: 安装 Nginx 和 Lua 模块
- 步骤 2: 创建 Lua 脚本用于参数校验
- 步骤 3: 配置 Nginx 使用 Lua 脚本
- 写法二: 状态码
- 写法三 : 返回自定义JSON
- 复杂的正则校验
- 步骤 4: 测试和验证
- ngx.HTTP_* 枚举值

概述
一个不使用 OpenResty 的 Nginx 集成 Lua 脚本的方案,用于对 POST 请求参数进行校验。
指令 | 所处处理阶段 | 使用范围 | 解释 |
---|---|---|---|
init_by_lua / init_by_lua_file | loading-config | http | Nginx Master进程加载配置时执行;通常用于初始化全局配置/预加载Lua模块 |
init_worker_by_lua / init_worker_by_lua_file | starting-worker | http | 每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua 之后调用;通常用于定时拉取配置/数据,或者后端服务的健康检查 |
set_by_lua / set_by_lua_file | rewrite | server, server if, location, location if | 设置Nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快。 |
rewrite_by_lua / rewrite_by_lua_file | rewrite | http, server, location, location if | rewrite阶段处理,可以实现复杂的转发/重定向逻辑。 |
access_by_lua / access_by_lua_file | access | http, server, location, location if | 请求访问阶段处理,用于访问控制。 |
content_by_lua / content_by_lua_file | content | location, location if | 内容处理器,接收请求处理并输出响应。 |
header_filter_by_lua / header_filter_by_lua_file | output-header-filter | http, server, location, location if | 设置header和cookie。 |
body_filter_by_lua / body_filter_by_lua_file | output-body-filter | http, server, location, location if | 对响应数据进行过滤,比如截断、替换。 |
log_by_lua / log_by_lua_file | log | http, server, location, location if | log阶段处理,比如记录访问量/统计平均响应时间。 |
步骤 1: 安装 Nginx 和 Lua 模块
玩转 Nginx 之:使用 Lua 扩展 Nginx 功能
步骤 2: 创建 Lua 脚本用于参数校验
创建一个 Lua 脚本,位于 /opt/nginx/lib/lua/validate_params.lua
(路径根据nginx.conf中的位置调整):
-- validate_params.lua
local function validate_post_params()ngx.req.read_body()local args = ngx.req.get_post_args()if not args.username or #args.username < 3 thenngx.status = ngx.HTTP_BAD_REQUESTngx.say("Username must be at least 3 characters long")return falseendif not args.password or #args.password < 6 thenngx.status = ngx.HTTP_BAD_REQUESTngx.say("Password must be at least 6 characters long")return falseendreturn true
endreturn {validate_post_params = validate_post_params
}
步骤 3: 配置 Nginx 使用 Lua 脚本
在 Nginx 配置文件中,使用 Lua 脚本来校验 POST 请求参数。修改 nginx.conf` ,增加 Lua 配置:
user root;
worker_processes 1;#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;lua_package_path "/opt/nginx/lib/lua/?.lua;;";lua_need_request_body on; # 启用请求体读取log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log logs/access.log main;error_log logs/error.log ;sendfile on;keepalive_timeout 65;server {listen 28443;server_name localhost;access_log logs/host.access.log main;location / {root html;index index.html index.htm;}location /api {content_by_lua_block {local validator = require("validate_params")if validator.validate_post_params() thenngx.say("Validation passed")end}}}
}
写法二: 状态码
lua
-- validate_params.lua
local function validate_post_params()ngx.req.read_body()local args = ngx.req.get_post_args()-- 验证用户名if not args.username or #args.username < 3 thenreturn ngx.HTTP_BAD_REQUEST, "Invalid username"end-- 验证密码if not args.password or #args.password < 6 thenreturn ngx.HTTP_BAD_REQUEST, "Invalid password"end-- 验证通过return ngx.HTTP_OK, "Validation successful"
endreturn {validate = validate_post_params
}
nginx.conf location config
location /api {content_by_lua_block {local validator = require("validate_params")local status, message = validator.validate()ngx.status = statusngx.say(status)ngx.say(message)if status ~= ngx.HTTP_OK thenngx.exit(status)end-- 继续后续业务逻辑}}
写法三 : 返回自定义JSON
如果不使用 cjson 库,我们可以手动构造 JSON 字符串。这种方法虽然不如使用专门的 JSON 库灵活,但对于简单的情况来说是足够的。
-- validate_params.lua
local function validate_post_params()ngx.req.read_body()local args = ngx.req.get_post_args()if not args.username or #args.username < 3 thenngx.status = ngx.HTTP_BAD_REQUESTngx.say("Username must be at least 3 characters long")return falseendif not args.password or #args.password < 6 thenngx.status = ngx.HTTP_BAD_REQUEST-- 创建 JSON 字符串local json_response = string.format('{"status":"%s","message":"%s"}',ngx.status, "Password must be at least 6 characters long")-- 设置响应头为 JSONngx.header.content_type = "application/json"-- 输出 JSON 响应ngx.say(json_response)return falseendreturn true
endreturn {validate_post_params = validate_post_params
}
这段代码会返回相同格式的 JSON:
{"status": "400","message": "Password must be at least 6 characters long"
}
几点说明:
-
使用 Lua 的
string.format()
函数来构造 JSON 字符串。这种方法适用于简单的 JSON 结构。 -
注意要正确处理字符串中的特殊字符,特别是引号。在这个例子中,我们的消息没有特殊字符,但在实际应用中可能需要进行转义。
-
仍然设置响应头的 content-type 为 “application/json”。
-
使用
ngx.say()
输出构造的 JSON 字符串。
这种方法的优点是不依赖额外的库,缺点是对于复杂的 JSON 结构可能会变得难以维护。如果需要处理更复杂的 JSON 数据,或者需要频繁地进行 JSON 操作,最好还是使用专门的 JSON 库(如 cjson 或 dkjson)。
location /api {content_by_lua_block {local validator = require("validate_params")if validator.validate_post_params() thenngx.say("Validation passed")end}}
复杂的正则校验
-- validate_params.lua-- 用户名验证函数
local function validate_username(username)-- 基础检查if not username or username == "" thenreturn false, "Username cannot be empty"end-- 长度检查local length = string.len(username)if length < 3 thenreturn false, "Username is too short (minimum 3 characters)"endif length > 20 thenreturn false, "Username is too long (maximum 20 characters)"end-- 检查是否包含空格if string.find(username, "%s") thenreturn false, "Username cannot contain spaces"end-- 正则表达式检查(只允许字母、数字、下划线,必须以字母开头)local pattern = "^[A-Za-z][A-Za-z0-9_]*$"if not ngx.re.match(username, pattern) thenreturn false, "Username must start with a letter and can only contain letters, numbers and underscore"end-- 检查保留字local reserved_words = {"admin", "root", "system", "user","moderator", "administrator"}local username_lower = string.lower(username)for _, word in ipairs(reserved_words) doif username_lower == word thenreturn false, "This username is reserved"endendreturn true, nil
end-- JSON响应函数
local function send_json_response(status, message)ngx.status = statusngx.header.content_type = "application/json"local json_response = string.format('{"status":"%s","message":"%s"}', status, message)ngx.say(json_response)
end-- 主验证函数
local function validate_post_params()ngx.req.read_body()local args = ngx.req.get_post_args()-- 验证用户名if not args.username thensend_json_response(ngx.HTTP_BAD_REQUEST, "Username is required")return falseendlocal is_valid, error_message = validate_username(args.username)if not is_valid thensend_json_response(ngx.HTTP_BAD_REQUEST, error_message)return falseend-- 验证密码if not args.password or #args.password < 6 thensend_json_response(ngx.HTTP_BAD_REQUEST, "Password must be at least 6 characters long")return falseendreturn true
end-- 导出模块
return {validate_post_params = validate_post_params
}
location /api {content_by_lua_block {local validator = require("validate_params")if validator.validate_post_params() thenngx.say("Validation passed")end}}
- 有效的用户名和密码:
curl -X POST http://localhost:28443/api -d "username=validuser&password=validpass123"
预期结果:成功(具体响应取决于你的成功处理逻辑)
- 用户名太短:
curl -X POST http://localhost:28443/api -d "username=ab&password=validpass123"
预期结果:
{"status":"400","message":"Username is too short (minimum 3 characters)"}
- 用户名太长:
curl -X POST http://localhost:28443/api -d "username=thisusernameiswaytoolong&password=validpass123"
预期结果:
{"status":"400","message":"Username is too long (maximum 20 characters)"}
- 用户名包含空格:
curl -X POST http://localhost:28443/api -d "username=invalid user&password=validpass123"
预期结果:
{"status":"400","message":"Username cannot contain spaces"}
- 用户名不以字母开头:
curl -X POST http://localhost:28443/api -d "username=1invaliduser&password=validpass123"
预期结果:
{"status":"400","message":"Username must start with a letter and can only contain letters, numbers and underscore"}
- 用户名包含非法字符:
curl -X POST http://localhost:28443/api -d "username=invalid@user&password=validpass123"
预期结果:
{"status":"400","message":"Username must start with a letter and can only contain letters, numbers and underscore"}
- 用户名是保留字:
curl -X POST http://localhost:28443/api -d "username=admin&password=validpass123"
预期结果:
{"status":"400","message":"This username is reserved"}
- 密码太短:
curl -X POST http://localhost:28443/api -d "username=validuser&password=short"
预期结果:
{"status":"400","message":"Password must be at least 6 characters long"}
- 缺少用户名:
curl -X POST http://localhost:28443/api -d "password=validpass123"
预期结果:
{"status":"400","message":"Username is required"}
- 缺少密码:
curl -X POST http://localhost:28443/api -d "username=validuser"
预期结果:
{"status":"400","message":"Password must be at least 6 characters long"}
步骤 4: 测试和验证
-
重启 Nginx:
sudo systemctl restart nginx
-
发送 POST 请求:
可以使用curl
或 Postman 测试:
[root@hcss-ecs-917b sbin]# curl -X POST http://localhost:28443/api -d "username=test&password=123456"
Validation passed
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]# curl -X POST http://localhost:28443/api -d "username=test&password=1"
Password must be at least 6 characters long
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]# curl -X POST http://localhost:28443/api -d "username=t&password=1"
Username must be at least 3 characters long
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]# curl -X POST http://localhost:28443/api
Username must be at least 3 characters long
[root@hcss-ecs-917b sbin]#
[root@hcss-ecs-917b sbin]#
ngx.HTTP_* 枚举值
在 OpenResty/Nginx 中,ngx.HTTP_* 常用的状态码枚举值如下:
- 成功类状态码:
ngx.HTTP_OK -- 200 成功
ngx.HTTP_CREATED -- 201 已创建
ngx.HTTP_NO_CONTENT -- 204 无内容
- 重定向类:
ngx.HTTP_MOVED_TEMPORARILY -- 302 临时重定向
ngx.HTTP_MOVED_PERMANENTLY -- 301 永久重定向
ngx.HTTP_SEE_OTHER -- 303 其他位置
ngx.HTTP_NOT_MODIFIED -- 304 未修改
- 客户端错误类:
ngx.HTTP_BAD_REQUEST -- 400 错误请求
ngx.HTTP_UNAUTHORIZED -- 401 未授权
ngx.HTTP_FORBIDDEN -- 403 禁止访问
ngx.HTTP_NOT_FOUND -- 404 未找到
ngx.HTTP_METHOD_NOT_ALLOWED -- 405 方法不允许
ngx.HTTP_REQUEST_TIMEOUT -- 408 请求超时
ngx.HTTP_CONFLICT -- 409 冲突
ngx.HTTP_GONE -- 410 资源已不存在
- 服务器错误类:
ngx.HTTP_INTERNAL_SERVER_ERROR -- 500 内部服务器错误
ngx.HTTP_NOT_IMPLEMENTED -- 501 未实现
ngx.HTTP_BAD_GATEWAY -- 502 网关错误
ngx.HTTP_SERVICE_UNAVAILABLE -- 503 服务不可用
ngx.HTTP_GATEWAY_TIMEOUT -- 504 网关超时
常用示例:
-- 成功响应
ngx.status = ngx.HTTP_OK
ngx.say("Success")-- 参数错误
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say("Invalid parameters")-- 未授权
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say("Authentication required")-- 服务器错误
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say("Server error occurred")
推荐使用场景:
- 验证类:使用 400-409
- 身份认证:使用 401-403
- 资源相关:使用 404-410
- 服务器错误:使用 500-504
建议根据具体业务场景选择最精准的状态码。
相关文章:

Nginx - 整合lua 实现对POST请求的参数拦截校验(不使用Openresty)
文章目录 概述步骤 1: 安装 Nginx 和 Lua 模块步骤 2: 创建 Lua 脚本用于参数校验步骤 3: 配置 Nginx 使用 Lua 脚本写法二: 状态码写法三 : 返回自定义JSON复杂的正则校验 步骤 4: 测试和验证ngx.HTTP_* 枚举值 概述 一个不使用 OpenResty 的 Nginx 集…...

互联网直播点播平台EasyDSS无人机视频推拉流技术实现工地远程监控巡检直播
在建筑行业,施工现场的安全管理和实时监控一直是项目管理中的重点。随着技术的进步,无人机工地直播技术成为了一种新兴的解决方案,它不仅能够提高施工透明度,还能够加强现场安全管理。EasyDSS作为一种先进的流媒体技术平台&#x…...

Unity3D 基于GraphView实现的节点编辑器框架详解
前言 在Unity3D游戏开发中,节点编辑器是一种强大的工具,它允许开发者以可视化的方式创建和编辑复杂的逻辑和流程。Unity提供了一个强大的UI工具包——GraphView,它使得创建自定义节点编辑器变得相对简单。本文将详细介绍如何使用GraphView实…...

【C++】开源:Armadillo数值计算库配置与使用
😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Armadillo数值计算库配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 文章目录 :smirk:1. Armadillo介绍:blush:2. 环境配置:s…...

HackMyVM-Airbind靶机的测试报告
目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、Getshell 3、提权 使用ipv6绕过iptables 四、结论 一、测试环境 1、系统环境 渗透机:kali2021.1(192.168.101.127) 靶 机:debian(192.168.101.11…...

C语言----函数
目录 1. 定义: 2.三要素 3.格式 4. 函数声明 5. 函数调用 6.函数传参 6.1. 值传递 6.2. 地址传递 6.3. 数组传递 string函数族 1.strcpy 2. strlen 3. strcat 4.strcmp 递归函数 1. 定义: 一个完成特定功能的代码模块 2.三要素 功能、…...

MySQL图形化界面工具--DataGrip
之前介绍了在命令行进行操作,但是不够直观,本次介绍图形化界面工具–DataGrip。 安装DataGrip 官网链接:官网下载链接 常规的软件安装流程。 参考链接:DataGrip安装 使用DataGrip 添加数据源: 第一次使用最下面会…...

PyTorch AMP 混合精度中grad_scaler.py的scale函数解析
PyTorch AMP 混合精度中的 scale 函数解析 混合精度训练(AMP, Automatic Mixed Precision)是深度学习中常用的技术,用于提升训练效率并减少显存占用。在 PyTorch 的 AMP 模块中,GradScaler 类负责动态调整和管理损失缩放因子&…...

【Ubuntu20.04】Apollo10.0 Docker容器部署+常见错误解决
官方参考文档【点击我】 Apollo 10.0 版本开始,支持本机和Docker容器两种部署方式。 如果您使用本机部署方式,建议使用x86_64架构的Ubuntu 22.04操作系统或者aarch64架构的Ubuntu 20.04操作系统。 如果您使用Docker容器部署方式,可以使用x…...

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)
****非斜体正文为原文献内容(也包含笔者的补充),灰色块中是对文章细节的进一步详细解释! 3.1.2 基于注意力的解释(Attention-Based Explanation) 注意力机制可以揭示输入数据中各个部分之间的关系&#…...

朱姆沃尔特隐身战舰:从失败到威慑
前言 "朱姆沃尔特"号驱逐舰是美国海军雄心勃勃的项目,旨在重塑未来海战。它融合了隐身、自动化和强大火力,然而由于技术问题和预算超支,原计划建造32艘的目标被大幅缩减,最终只建造了三艘。该舰的设计特点包括“穿浪逆船…...

免费分享 | 基于极光优化算法PLO优化宽度学习BLS实现光伏数据预测算法研究附Matlab代码
研究内容 宽度学习系统(BLS)简介: BLS是一种新型的神经网络结构,由增强节点(Enhancement Nodes, ENs)和特征节点(Feature Nodes, FNs)组成,具有结构简单、训练速度快、泛…...

logback日志文件多环境配置路径
项目中遇到问题,springboot项目 本地jar包部署到现场后,经常遇到现场的日志存放的路径会更改,经过查阅,有两种方式,下面简单说明一下。 一、第一种 启动jar包时 添加参数 --logging.configF:\hgtest\config\logback.x…...

面试高频:一致性hash算法
这两天看到技术群里,有小伙伴在讨论一致性hash算法的问题,正愁没啥写的题目就来了,那就简单介绍下它的原理。下边我们以分布式缓存中经典场景举例,面试中也是经常提及的一些话题,看看什么是一致性hash算法以及它有那些…...

docker部署项目
docker部署项目 (加载tar包:docker image load -i mysql.tar) 一、jdk环境配置 1.jdk下载地址 --Java Archive | Oracle 中国 --选择好版本进入 --下载Linux x64 Compressed Archive的链接 2.解压 --创建文件夹:mkdir /ro…...

每天40分玩转Django:Django Celery
Django Celery 一、知识要点概览表 模块知识点掌握程度要求Celery基础配置、任务定义、任务执行深入理解异步任务任务状态、结果存储、错误处理熟练应用周期任务定时任务、Crontab、任务调度熟练应用监控管理Flower、任务监控、性能优化理解应用 二、基础配置实现 1. 安装和…...

df.groupby(pd.Grouper(level=1)).sum()
df.groupby(pd.Grouper(level1)).sum() 在 Python 中的作用是根据 DataFrame 的某一索引级别进行分组,并计算每个分组的总和。具体来说: df.groupby(...):这是 pandas 的分组操作,按照指定的规则将 DataFrame 分组。 pd.Grouper(…...
运动控制探针功能详细介绍(CODESYS+SV63N伺服)
汇川AM400PLC和禾川X3E伺服EtherCAT通信 汇川AM400PLC和禾川X3E伺服EtherCAT通信_汇川ethercat通信-CSDN博客文章浏览阅读1.2k次。本文详细介绍了如何使用汇川AM400PLC通过EtherCAT总线与禾川X3E伺服进行通信。包括XML硬件描述文件的下载与安装,EtherCAT总线的启用,从站添加…...

C语言基础18(GDB调试)
文章目录 GDBGDB概述什么是GDB**GDB**的主要功能 GDB的启动GDB常见的启动方式 GDB的退出GDB的常用命令GDB查看源代码指令———list(1)**GDB** 查看设置**------info****GDB** 查看内存**GDB** 设置断点**---break (b)****GDB** 设置观察点**---watch****GDB** 程序调试 GDB完整…...

《向量数据库指南》——应对ElasticSearch挑战,拥抱Mlivus Cloud的新时代
在当今数据驱动的商业环境中,向量数据库的应用正变得愈加重要。随着人工智能和机器学习的快速发展,尤其是在自然语言处理、图像识别及推荐系统等领域,向量数据库以其强大的存储和检索能力,迎来了广泛的应用机会。然而,在实际应用中,企业在选择和实施向量数据库方案时,常…...

c++的stl库中stack的解析和模拟实现
目录 1.stack的介绍和使用 1.1stack的介绍 1.2stack的使用 2.stack的模拟实现 1.stack的介绍和使用 1.1stack的介绍 1. stack 是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 2. stac…...

C语言——字符函数和内存函数
目录 前言 字符函数 1strlen 模拟实现 2strcpy 模拟实现 3strcat 模拟实现 4strcmp 模拟实现 5strncpy 模拟实现 6strncat 模拟实现 7strncmp 模拟实现 8strstr 模拟实现 9strtok 10strerror 11大小写字符转换函数 内存函数 1memcpy 模拟实现 2…...

查询docker overlay2文件夹下的 c7ffc13c49xxx是哪一个容器使用的
问题背景 查询docker overlay2文件夹下的 c7ffc13c49xxx是哪一个容器使用的 [root@lnops overlay2]# du -sh * | grep G 1.7G 30046eca3e838e43d16d9febc63cc8f8bb3d327b4c9839ca791b3ddfa845e12e 435G c7ffc13c49a43f08ef9e234c6ef9fc5a3692deda3c5d42149d0070e9d8124f71 1.…...

Golang的容器编排实践
Golang的容器编排实践 一、Golang中的容器编排概述 作为一种高效的编程语言,其在容器编排领域也有着广泛的运用。容器编排是指利用自动化工具对容器化的应用进行部署、管理和扩展的过程,典型的容器编排工具包括Docker Swarm、Kubernetes等。在Golang中&a…...

【51项目】51单片机自制小霸王游戏机
视频演示效果: 纳新作品——小霸王游戏机 目录: 目录 视频演示效果: 目录: 前言:...

ArkTs之NAPI学习
1.Node-api组成架构 为了应对日常开发经的网络通信、串口访问、多媒体解码、传感器数据收集等模块,这些模块大多数是使用c接口实现的,arkts侧如果想使用这些能力,就需要使用node-api这样一套接口去桥接c代码。Node-api整体的架构图如下&…...

【数据库初阶】MySQL中表的约束(上)
🎉博主首页: 有趣的中国人 🎉专栏首页: 数据库初阶 🎉其它专栏: C初阶 | C进阶 | 初阶数据结构 亲爱的小伙伴们,大家好!在这篇文章中,我们将深入浅出地为大家讲解 MySQL…...

173. 矩阵距离 acwing -多路BFS
原题链接:173. 矩阵距离 - AcWing题库 给定一个 N行 M 列的 01矩阵 A,A[i][j] 与 A[k][l]]之间的曼哈顿距离定义为: dist(i,j,k,l)|i−k||j−l|| 输出一个 N 行 M 列的整数矩阵 B,其中: B[i][j]min1≤x≤N,1≤y≤M,A…...

Linux下部署Redis集群 - 一主二从三哨兵模式
三台服务器redis一主二从三哨兵模式搭建 最近使用到了redis集群部署,使用一主二从三哨兵集群部署redis,将自己部署的过程中的使用心得分享给大家,希望大家以后部署的过程减少一些坑。 服务器准备 3台服务器 ,确定主redis和从red…...

实战设计模式之建造者模式
概述 在实际项目中,我们有时会遇到需要创建复杂对象的情况。这些对象可能包含多个组件或属性,而且每个组件都有自己的配置选项。如果直接使用构造函数或前面介绍的工厂方法来创建这样的对象,可能会导致以下两个严重问题。 1、参数过多。当一个…...