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_fileloading-confighttpNginx Master进程加载配置时执行;通常用于初始化全局配置/预加载Lua模块
init_worker_by_lua / init_worker_by_lua_filestarting-workerhttp每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;通常用于定时拉取配置/数据,或者后端服务的健康检查
set_by_lua / set_by_lua_filerewriteserver, server if, location, location if设置Nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快。
rewrite_by_lua / rewrite_by_lua_filerewritehttp, server, location, location ifrewrite阶段处理,可以实现复杂的转发/重定向逻辑。
access_by_lua / access_by_lua_fileaccesshttp, server, location, location if请求访问阶段处理,用于访问控制。
content_by_lua / content_by_lua_filecontentlocation, location if内容处理器,接收请求处理并输出响应。
header_filter_by_lua / header_filter_by_lua_fileoutput-header-filterhttp, server, location, location if设置header和cookie。
body_filter_by_lua / body_filter_by_lua_fileoutput-body-filterhttp, server, location, location if对响应数据进行过滤,比如截断、替换。
log_by_lua / log_by_lua_fileloghttp, server, location, location iflog阶段处理,比如记录访问量/统计平均响应时间。

步骤 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"
}

在这里插入图片描述

几点说明:

  1. 使用 Lua 的 string.format() 函数来构造 JSON 字符串。这种方法适用于简单的 JSON 结构。

  2. 注意要正确处理字符串中的特殊字符,特别是引号。在这个例子中,我们的消息没有特殊字符,但在实际应用中可能需要进行转义。

  3. 仍然设置响应头的 content-type 为 “application/json”。

  4. 使用 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}}

在这里插入图片描述

  1. 有效的用户名和密码:
curl -X POST http://localhost:28443/api -d "username=validuser&password=validpass123"

预期结果:成功(具体响应取决于你的成功处理逻辑)

  1. 用户名太短:
curl -X POST http://localhost:28443/api -d "username=ab&password=validpass123"

预期结果:

{"status":"400","message":"Username is too short (minimum 3 characters)"}
  1. 用户名太长:
curl -X POST http://localhost:28443/api -d "username=thisusernameiswaytoolong&password=validpass123"

预期结果:

{"status":"400","message":"Username is too long (maximum 20 characters)"}
  1. 用户名包含空格:
curl -X POST http://localhost:28443/api -d "username=invalid user&password=validpass123"

预期结果:

{"status":"400","message":"Username cannot contain spaces"}
  1. 用户名不以字母开头:
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"}
  1. 用户名包含非法字符:
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"}
  1. 用户名是保留字:
curl -X POST http://localhost:28443/api -d "username=admin&password=validpass123"

预期结果:

{"status":"400","message":"This username is reserved"}
  1. 密码太短:
curl -X POST http://localhost:28443/api -d "username=validuser&password=short"

预期结果:

{"status":"400","message":"Password must be at least 6 characters long"}
  1. 缺少用户名:
curl -X POST http://localhost:28443/api -d "password=validpass123"

预期结果:

{"status":"400","message":"Username is required"}
  1. 缺少密码:
curl -X POST http://localhost:28443/api -d "username=validuser"

预期结果:

{"status":"400","message":"Password must be at least 6 characters long"}

步骤 4: 测试和验证

  1. 重启 Nginx

    sudo systemctl restart nginx
    
  2. 发送 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_* 常用的状态码枚举值如下:

  1. 成功类状态码:
ngx.HTTP_OK                 -- 200 成功
ngx.HTTP_CREATED            -- 201 已创建
ngx.HTTP_NO_CONTENT         -- 204 无内容
  1. 重定向类:
ngx.HTTP_MOVED_TEMPORARILY  -- 302 临时重定向
ngx.HTTP_MOVED_PERMANENTLY  -- 301 永久重定向
ngx.HTTP_SEE_OTHER          -- 303 其他位置
ngx.HTTP_NOT_MODIFIED       -- 304 未修改
  1. 客户端错误类:
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 资源已不存在
  1. 服务器错误类:
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")

推荐使用场景:

  1. 验证类:使用 400-409
  2. 身份认证:使用 401-403
  3. 资源相关:使用 404-410
  4. 服务器错误:使用 500-504

建议根据具体业务场景选择最精准的状态码。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/501057.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机中的时统卡功能和性能调优

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

GXUOJ-算法-补题:22级《算法设计与分析》第一次课堂练习

2.最大子数组和 问题描述 代码解答 #include<bits/stdc.h> using namespace std; const int N1005; int sum,n,a[N]; int res-1;int result(){for(int i0;i<n;i){if(sum<0) suma[i];else{suma[i];resmax(res,sum);}}return res; } int main(){cin>>n;for(i…

信息学奥赛一本通:1311:【例2.5】求逆序对

1311&#xff1a;【例2.5】求逆序对 时间限制: 1000 ms 内存限制: 65536 KB提交数:74572 通过数: 17809 【题目描述】 给定一个序列a1,a2,…,an&#xff0c;如果存在i<j并且ai>aj&#xff0c;那么我们称之为逆序对&#xff0c;求逆序对的数目。 【输入】 第一…

免登录游客卡密发放系统PHP网站源码

源码介绍&#xff1a; 这是一个简单易用的卡密验证系统&#xff0c;主要功能包括&#xff1a; 卡密管理和验证&#xff0c;多模板支持&#xff0c;响应式设计&#xff0c;验证码保护&#xff0c;防刷机制&#xff0c;简洁的用户界面&#xff0c; 支持自定义模板&#xff0c;移…

关于 PPPOE技术的详细解释

PPPoE&#xff08;以太网点对点协议&#xff09;是一种网络协议&#xff0c;它通过光纤将点对点协议&#xff08;PPP&#xff09;封装以实现宽带接入点。PPPoE主要用于ADSL和光纤等宽带接入技术中&#xff0c;它允许多个用户共享同一个交换机连接&#xff0c;同时为每个用户提供…

C# 服务应用研究

文章目录 创建Windows Service项目选中serviceInstaller1组件&#xff0c;查看属性生成和发布服务安装服务卸载服务重新再安装服务停止服务再次卸载服务调试服务 创建Windows Service项目 选中serviceInstaller1组件&#xff0c;查看属性 生成和发布服务 安装服务 卸载服务 重新…

MySQL中distinct和group by去重的区别

MySQL中distinct和group by去重的区别 在MySQL中&#xff0c;我们经常需要对查询结果进行去重&#xff0c;而DISTINCT和GROUP BY是实现这一功能的两种常见方法。虽然它们在很多情况下可以互换使用&#xff0c;但它们之间还是存在一些差异的。接下来&#xff0c;我们将通过创建测…

三维场景重建3D高斯点渲染复现

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;传知代码 欢迎大家点赞收藏评论&#x1f60a; 目录 三维场景重建概述MVSNetNerf3D gaussian-splatting 效果演示3D gaussian-splatting原理高斯分布的数学基础渲染过程优化与加速 3D Gaussian-sp…

小波滤波器处理一维信号-附Matlab源代码

⭕⭕ 目 录 ⭕⭕ 一、引言二、多分辨率分析原理2.1 概念解析2.2 尺度函数和小波函数的关系2.3 滤波器本质2.4 二维正交多分辨率分析 三、一维信号小波滤波器处理实例四、Matlab程序获取与验证 一、引言 Fourier变换无法同时描述和定位信号在时间和频率上的突变部分。小波变换的…

log4j2的Strategy、log4j2的DefaultRolloverStrategy、删除过期文件

文章目录 一、DefaultRolloverStrategy1.1、DefaultRolloverStrategy节点1.1.1、filePattern属性1.1.2、DefaultRolloverStrategy删除原理 1.2、Delete节点1.2.1、maxDepth属性 二、知识扩展2.1、DefaultRolloverStrategy与Delete会冲突吗&#xff1f;2.1.1、场景一&#xff1a…

vue v-for 数据增加页面不刷新

<div style"float:left;border:1px solid red;height:100px;width:600px;"><el-form-item label"多语言配置" style"width:700px;" prop"validTanleHead"><el-input style"width: 180px" placeholder"请…

Mac 版本向日葵退出登录账号

找遍整个软件&#xff0c;Mac 版本的向日葵甚至逆天到没有提供退出登录的功能… 随后我发现可以直接删除向日葵的配置文件达到退出登录的效果&#xff0c;具体操作如下&#xff1a; cd /etc # 确认存在 orayconfig.conf 文件 ls orayconfig.conf  # 删除 sudo rm -f oray…

双目视觉:reprojectImageTo3D函数

前言 reprojectImageTo3D 是 OpenCV 中用于从视差图生成三维点云的函数。它的原理是利用视差图和相机的校准参数&#xff0c;通过三角测量法&#xff0c;计算每个像素对应的三维坐标。以下内容根据源码分析所写&#xff0c;觉得可以的话&#xff0c;点赞收藏哈&#xff01;&am…

苍穹外卖04——Redis初入门 在店铺打烊or营业状态管理功能中的使用

Redis入门 redis简介 它以键值对的形式存储数据在内存中,并且以极高的性能和灵活性而著称,通常用于缓存、消息代理以及持久化数据。 - 基于内存存储,读写性能高- 适合存储热点数据(热点商品、资讯、新闻)- 企业应用广泛Windows版下载地址:https://github.com/microsoft…

No.1十六届蓝桥杯备战|第一个C++程序|cin和cout|命名空间

第一个C程序 基础程序 使用DevC5.4.0 写一个C程序 在屏幕上打印hello world #include <iostream> using namespace std;int main() {cout << "hello world" << endl;return 0; } 运行这个C程序 F9->编译 F10->运行 F11->编译运行 mai…

springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)

引言&#xff1a; 该类博客的学习是基于b站黑马视频springbootvue视频学习&#xff01;具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍&#xff08;需求&#xff09;。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…

LoRA微调系列笔记

系列文章目录 第一章&#xff1a;LoRA微调系列笔记 第二章&#xff1a;Llama系列关键知识总结 第三章&#xff1a;LLaVA模型讲解与总结 文章目录 系列文章目录LoRA&#xff1a;Low-Rank Adaptation of Large Language Models目的&#xff1a;依据&#xff1a;优势&#xff1a;…

Python - 游戏:飞机大战;数字华容道

Pygame是一个利用SDL库的写的游戏库&#xff0c;SDL呢&#xff0c;全名Simple DirectMedia Layer&#xff0c;是一位叫做Sam Lantinga的大牛写的 SDL是用C写的&#xff0c;不过它也可以使用C进行开发&#xff0c;当然还有很多其它的语言&#xff0c;Pygame就是Python中使用它的…

【JVM】总结篇-字节码篇

字节码篇 Java虚拟机的生命周期 JVM的组成 Java虚拟机的体系结构 什么是Java虚拟机 虚拟机&#xff1a;指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 &#xff0c;是物理机的软件实现。常用的虚拟机有VMWare&#xff0c;Visual Box&…

GitHub 及 GitHub Desktop 详细使用教程(通俗易懂)

目录 Δ前言 一、Github教程 1.什么是Github&#xff1f; 2.仓库和对仓库的操作&#xff1a; 2.1 Repository&#xff08;仓库&#xff09; 2.2 Fork&#xff08;派生&#xff09; 2.3 Star&#xff08;收藏&#xff09; 2.4 Watch&#xff08;追番&#xff09; 2.5 Issue&am…