动态控制入口:掌握OpenResty的11把编程金钥匙 2025-08-08 服务器 暂无评论 41 次阅读 刚接触OpenResty时,我被各种`*-by_lua`指令绕晕了——直到有一天突然顿悟:它们就是乐高积木啊! 每个指令对应请求处理的一个环节,我们只需要把业务逻辑"插"到合适的位置。 > 这些`*-by_lua`指令如同精密的瑞士军刀,让你在请求生命周期的各个阶段精准植入业务逻辑 #一、指令全景图(按执行顺序)  #二、关键阶段深度解析 ##1. 请求启程前(单次执行) `init_by_lua*` - 执行时机:Master进程启动时 - 典型应用: ``` http { init_by_lua_block { -- 加载全局配置 require "config_loader" -- 预热共享内存 ngx.shared.cache:set("boot_time", os.time()) } } ``` `init_worker_by_lua*` - 执行时机:每个Worker启动时 - 注意点:worker数量=CPU核心数,会并行执行 - 典型应用: ``` init_worker_by_lua_block { -- 启动健康检查定时器 local check = function() ngx.log(ngx.INFO, "健康检查中...") -- 检测后端服务状态 end ngx.timer.at(10, check) -- 每10秒执行 } ``` ##2. SSL握手阶段 `ssl_certificate_by_lua*` - 独特优势:动态加载TLS证书 - 应用场景:多域名证书管理、证书自动化续签 - 安全示例: ``` server { ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" -- 基于SNI选择证书 local cert = query_cert(ssl.server_name()) ssl.set_cert(cert) -- 强制TLS1.3 ssl.set_protocols("TLSv1.3") } } ``` ##3. 请求处理阶段(核心三剑客) `set_by_lua*` - 重要限制:禁用阻塞操作 - 典型场景:快速计算变量值 ``` location / { set_by_lua $signature ' local args = ngx.req.get_uri_args() return ngx.md5(args.id.."SALT") '; proxy_set_header X-Sign $signature; } ``` `rewrite_by_lua*` - 核心用途:URI重写和流量调度 - 高级技巧: ``` rewrite_by_lua_block { -- A/B测试分流 if math.random() < 0.3 then ngx.req.set_uri("/v2"..ngx.var.uri) end -- 动态设置upstream ngx.var.upstream = choose_backend(ngx.var.host) } ``` `access_by_lua*` - 安全防线:认证/授权/限流 - 三合一实现: ``` access_by_lua_block { -- 认证 if not check_jwt(ngx.var.cookie_token) then return ngx.exit(401) end -- 限流 local limiter = require "resty.limit.count" if limiter.exceeded(ngx.var.remote_addr, 100) then ngx.header["Retry-After"] = "60" return ngx.exit(429) end } ``` ##4. 内容生成阶段 `content_by_lua*` - 定位:替代Nginx的proxy_pass和静态文件服务 - 最佳实践: ``` content_by_lua_block { -- 并发查询优化 local user_co = ngx.thread.spawn(get_user_info) local orders_co = ngx.thread.spawn(get_user_orders) -- 等待结果 local results = { ngx.thread.wait(user_co, orders_co) } -- 流式输出 ngx.print(cjson.encode(results)) ngx.eof() -- 关闭连接 } ``` ##5. 负载均衡阶段 `balancer_by_lua*` - 颠覆性功能:动态服务发现 - 智能路由示例: ``` balancer_by_lua_block { local balancer = require "ngx.balancer" -- 获取健康节点 local healthy_nodes = healthcheck.get_available("service_A") -- 一致性哈希路由 local idx = ngx.crc32(ngx.var.remote_addr) % #healthy_nodes balancer.set_current_peer(healthy_nodes[idx].ip, healthy_nodes[idx].port) } ``` ##6. 响应处理阶段 `header_filter_by_lua*` - 核心用途:统一设置HTTP头 - 安全加固: ``` header_filter_by_lua_block { -- 删除敏感头 ngx.header.Server = nil -- 添加安全策略 ngx.header["Content-Security-Policy"] = "default-src 'self'" -- 跨域控制 ngx.header["Access-Control-Allow-Origin"] = "*" } ``` `body_filter_by_lua*` - 流式处理:分块修改响应体 - 典型场景: ``` body_filter_by_lua_block { local chunk = ngx.arg[1] ifnot chunk thenreturnend -- 敏感信息脱敏 chunk = chunk:gsub("password=%w+", "password=******") -- 尾部插入统计信息 if ngx.arg[2] then-- 最后一块 chunk = chunk.."\n" end ngx.arg[1] = chunk } ``` ##7. 日志终结阶段 `log_by_lua*` - 数据革命:替换传统Nginx日志 - 实时管道示例: ``` log_by_lua_block { -- 结构化日志 local log = { time = ngx.localtime(), latency = ngx.now() - ngx.req.start_time(), status = ngx.status, upstream = ngx.var.upstream_addr } -- 发送到Kafka local kafka = require "resty.kafka" local producer = kafka:new("kafka_cluster") producer:send("nginx_logs", nil, cjson.encode(log)) } ``` #三、阶段选择黄金定律 1. 内容生成 → `content_by_lua*` 2. 权限校验 → `access_by_lua*` 3. 路由改写 → `rewrite_by_lua*` 4. 响应装饰 → `header_filter_by_lua*` + `body_filter_by_lua*` 5. 后处理 → `log_by_lua*` #四、避坑指南 ``` location /api { # 正确示范 - 各司其职 rewrite_by_lua_file lua/router.lua; # 路由 access_by_lua_block { # 认证 auth.check(ngx.var.token) } content_by_lua_file lua/api.lua; # 核心逻辑 # 错误示范 - 不要多个content阶段处理器 # proxy_pass http://backend; } ``` > 提示:在开发环境使用`lua_code_cache off;`实现代码热重载,生产环境务必改为`on` 掌握这11把金钥匙,你将能充分发挥OpenResty的强大能力! "当你真正理解这些指令的设计哲学时,就会明白: OpenResty不是Nginx的魔改版,而是一套全新的编程范式" 转自https://mp.weixin.qq.com/s/aSa5N79bnHvCsdZSv32_zQ 标签: openresty 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。