Nginx 11月前

Nginx 如何集成 Lua 或其他语言插件

作者头像 刘宇帅
1674 0

Nginx 虽然以高性能和模块化著称,但它本身并不具备处理复杂逻辑或动态内容的能力。为了增强 Nginx 的可编程性,我们可以通过集成 Lua 脚本或其他语言插件,让 Nginx 拥有“业务逻辑大脑”。

本文将以 Lua 为核心,介绍如何在 Nginx 中集成编程能力,并扩展到其他语言插件的接入方式。

目录

一、为什么需要在 Nginx 中编程

默认情况下,Nginx 的行为由配置文件决定,缺乏“逻辑判断能力”,这在以下场景中有明显限制:

  • 根据请求内容动态转发或处理
  • 实现接口级别的灰度发布、A/B 测试
  • 实时访问控制(如防刷、限流规则)
  • 高性能缓存控制与签名校验
  • 自定义认证逻辑或数据过滤

通过嵌入脚本语言,我们可以灵活地扩展 Nginx 的功能,使其更适合业务型中间层或边缘计算场景。

二、常用的扩展方式概览

在 Nginx 中集成脚本或其他语言,常见方式如下:

  1. Lua(最主流)
    使用 ngx_http_lua_module 或 OpenResty 集成,性能高、社区成熟。

  2. Python / Go / Node.js
    不能嵌入 Nginx 内部,但可以通过 Nginx 转发到本地服务或 FastCGI 网关间接集成。

  3. C/C++ 模块扩展
    原生模块方式开发,性能最强,但开发成本高,调试困难。

其中,Lua 是唯一可以与 Nginx 原生融合的脚本语言

三、使用 Lua 插件的推荐方式:OpenResty

OpenResty 是基于 Nginx 打包的 Web 平台,内置了 LuaJIT 和一系列 Nginx 模块,可让你在配置文件中直接书写 Lua 脚本。

安装方式(以 Ubuntu 为例):

sudo apt install openresty

配置示例:

server {
    listen 8080;

    location /hello {
        default_type text/plain;
        content_by_lua_block {
            ngx.say("Hello from Lua inside Nginx!")
        }
    }
}

启动:

sudo openresty -p `pwd` -c nginx.conf

也可以使用普通 Nginx + Lua 模块的方式编译:

./configure --with-http_lua_module
make && make install

但不建议自行编译,OpenResty 更推荐且更稳定

四、Lua 常见用法示例

以下是一些常见的 Lua 插件用法:

请求重写逻辑

rewrite_by_lua_block {
    if ngx.var.arg_token ~= "123456" then
        return ngx.exit(403)
    end
}

动态转发

set_by_lua_block $backend {
    if ngx.var.arg_user == "vip" then
        return "backend1"
    else
        return "backend2"
    end
}

proxy_pass http://$backend;

自定义访问日志

log_by_lua_block {
    ngx.log(ngx.ERR, "Request to ", ngx.var.request_uri)
}

使用 Redis、MySQL 等

OpenResty 提供了很多第三方 Lua 库,例如:

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
red:connect("127.0.0.1", 6379)
red:set("key", "value")

只需使用 Lua 编写逻辑,就能在请求链路中读写外部服务。

五、Nginx 支持其他语言的方式

虽然 Nginx 只能原生集成 Lua,但可以借助以下方式集成其他语言:

反向代理到本地服务

通过 proxy_pass 将请求转发到 Node.js、Go、Python 等语言编写的服务:

location /ml-api/ {
    proxy_pass http://127.0.0.1:9000;
}

适合做机器学习服务、配置服务、数据服务等。

FastCGI 模式(如 PHP)

通过 fastcgi_pass 连接 PHP-FPM、Python-FCGI 等后端:

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    include fastcgi_params;
}

使用 uwsgi 或 scgi 模块

适用于 Python 的 Flask/Django 应用,可通过 uwsgi_pass 与 Nginx 集成。

这些方式都是“语言服务 + Nginx 反向代理”组合,适用于业务系统,不适用于高性能中间件层。

六、使用注意事项

  • Lua 代码运行在 Nginx 的 worker 进程中,必须避免阻塞式 I/O
  • 推荐使用 OpenResty,避免手动编译和模块兼容问题
  • Lua 脚本尽量精简,复杂逻辑应下放至后端服务
  • 调试 Lua 脚本推荐打开 error 日志或使用 ngx.log
  • 所有动态变量必须由 $ 开头或用 ngx.var

总结

在 Nginx 中集成 Lua 是一种非常灵活的方式,可以在不改动后端服务的前提下,完成复杂的请求处理逻辑。配合 OpenResty,你可以将 Nginx 变成一个具备轻量编程能力的“边缘网关”,广泛应用于 A/B 实验、限流、动态路由、安全校验等场景。

作者头像

刘宇帅

非著名程序员,全栈开发工程师,长期专注系统开发与架构设计。

提示

功能待开通!


暂无评论~

相关文章

浏览器报错 net::ERR_INCOMPLETE_CHUNKED_ENCODING

nginx服务器返回200但是浏览器报错 net::ERR_INCOMPLETE_CHUNKED_ENCODING 原因是nginx在获得后端服务器返回数据时,数据过大需要存在临时文件中,但是当前运行nginx用户,没有该文件的读写权限 导致的。 如何证实 可以查看nginx的日志,会有以下类似错误 2018/03/22 16:11:35 [crit] 9519#0: *339625 open() "/var/lib/nginx/tmp/fastcgi/5/02/0000000025" failed 很明显,nginx无法写/var/lib/nginx/tmp/fastcgi/5/02/000

Nginx 路由匹配

模式 含义 location = /uri = 表示精确匹配只有完全相等才会匹配成功 location ^~ /uri ^~ 表示对路由进行前缀匹配 location ~ /uri ~ 表示对路由进行正则匹配 location ~* /uri ~* 表示对路由进行不区分大小写的正则匹配 location /uri 不带任何修饰符也表示前缀匹配 location / 默认匹配,任何没有匹配到的uri 多个 location 配置的情况下匹配顺序为(匹配到某一等级就结束,同一规则时匹配长度长的优先): 首先精确匹配 = 其次前缀匹配 ^~ 其次是按文件中顺

Nginx日志配置推荐

推荐日志配置 log_format main 'remote_addr=[$remote_addr] http_x_forward=[$http_x_forwarded_for] time=[$time_local] request=[$request] ' 'status=[$status] byte=[$bytes_sent] elapsed=[$request_time] upstream_connect_time=[$upstream_connect_time] upstream_response_time=[$upstream_response_time] '

Nginx 反向代理常见问题汇总与解决方案

在使用 Nginx 做反向代理时,经常会遇到一些看似莫名其妙的问题,比如返回 502 错误、路径出错、真实 IP 丢失等等。本文总结了开发和部署中最常见的 Nginx 反向代理问题,并给出对应的排查和解决方案,帮助你快速定位和修复问题。 目录 一、502 Bad Gateway 二、路径拼接异常 三、获取不到真实客户端-IP 四、跨域请求失败 五、WebSocket 无法正常工作 六、请求体过大导致-413-错误 七、反向代理跳转失效 八、HTTPS-代理配置问题 九、文件下载异常或中断 十、缓存未生效或生效异常 总结 一、502 Bad Gateway 这个错误意味着 Nginx 无法成

Nginx 四层最佳配置

stream { log_format proxy 'time=[$time_local] remote_addr=[$remote_addr]' ' protocol=[$protocol] status=[$status] byte_send=[$bytes_sent] byte_received=[$bytes_received] ' 'session_time=[$session_time] upstream_addr=[$upstream_addr] ' 'upstream_