1. 为什么需要这样的网关?——从业务场景说起

某电商平台在促销活动期间,每秒遭遇数万请求冲击。工程师老王发现:突发流量中有30%是爬虫请求,部分接口被暴力破解,后台日志还混杂着大量过期API的调用记录。这正是现代网关需要解决的三大核心问题——请求过滤(限流防刷)、权限校验(接口保护)、API文档自动化(降低维护成本)。

http {
    lua_package_path "/usr/local/openresty/lualib/?.lua;;";
    
    # 共享字典用于限流统计
    lua_shared_dict rate_limit 10m;
    
    server {
        listen 80;
        
        location / {
            # 请求处理阶段声明
            access_by_lua_file conf/access_control.lua;
            content_by_lua_file conf/service_router.lua;
        }
    }
}

(注释说明:通过lua_shared_dict建立共享内存区域,access阶段处理鉴权逻辑,content阶段路由到具体服务)


2. 精准的流量手术刀——请求过滤实战

2.1 IP黑白名单控制

-- access_control.lua 片段
local black_ips = {"192.168.1.100", "10.0.0.205"} -- 静态黑名单
local client_ip = ngx.var.remote_addr

if ngx.shared.ip_blacklist:get(client_ip) then
    ngx.exit(403)
end

-- 动态封禁(演示10秒封禁)
if is_malicious_request() then
    ngx.shared.ip_blacklist:set(client_ip, true, 10)
end

(注释说明:结合内存字典实现动态封禁,避免修改配置重载)

2.2 令牌桶算法限流

-- rate_limit.lua
local limiter = require "resty.limit.req"
local rate = 100 -- 每秒100个请求
local burst = 50  -- 允许突发50个

local lim = limiter.new("rate_limit", rate, burst)
local delay, err = lim:incoming(client_ip, true)

if not delay then
    if err == "rejected" then
        ngx.exit(503)
    end
    ngx.log(ngx.ERR, "限流器错误: ", err)
end

(注释说明:采用漏桶算法实现平滑限流,burst参数应对突发流量)


3. 多维权限校验体系——不只是JWT那么简单

3.1 OAuth2.0接入示例

-- auth_validate.lua
local http = require "resty.http"
local cjson = require "cjson"

local function validate_token(token)
    local httpc = http.new()
    local res, err = httpc:request_uri("https://auth.server/check", {
        method = "POST",
        body = "token="..token,
        headers = {["Content-Type"] = "application/x-www-form-urlencoded"}
    })
    
    if not res then return nil, err end
    return cjson.decode(res.body)
end

(注释说明:与认证服务解耦,支持分布式鉴权)

3.2 API签名校验

-- signature.lua
local resty_hmac = require "resty.hmac"

local SECRET_KEY = "your_secret_2023"

local params = ngx.req.get_uri_args()
local sign = params.sign

local hmac = resty_hmac:new(SECRET_KEY, resty_hmac.ALGOS.SHA256)
hmac:update(ngx.var.request_uri)
local expect_sign = hmac:final()

if sign ~= expect_sign then
    ngx.log(ngx.WARN, "签名校验失败: ", sign)
    ngx.exit(401)
end

(注释说明:HMAC-SHA256实现防篡改校验)


4. 文档自动化——让代码自己说话

4.1 注解式文档采集

-- api_doc.lua
local apidoc = {}

function apidoc.collect()
    local route_info = {
        uri = ngx.var.uri,
        method = ngx.var.request_method,
        params = ngx.req.get_uri_args(),
        desc = "--@desc 用户信息查询接口\n--@param userId string 用户ID"
    }
    ngx.shared.api_docs:set(ngx.var.uri, cjson.encode(route_info))
end

function apidoc.generate()
    local docs = {}
    for _, key in pairs(ngx.shared.api_docs:get_keys()) do
        docs[#docs+1] = cjson.decode(ngx.shared.api_docs:get(key))
    end
    return cjson.encode(docs)
end

(注释说明:通过Lua注解自动提取接口元数据)

4.2 Swagger集成输出

location /swagger.json {
    content_by_lua_block {
        local apidoc = require "api_doc"
        ngx.header["Content-Type"] = "application/json"
        ngx.say(apidoc.generate())
    }
}

(注释说明:自动生成标准Swagger文档,接入现有API管理平台)


5. 关键问题深度分析

5.1 应用场景矩阵

  • 金融系统:多重签名+动态限流
  • IoT设备:长连接会话管理
  • 微服务架构:统一入口治理

5.2 技术选型对比

方案 性能优势 可扩展性
OpenResty 10万+ QPS Lua模块化
SpringCloud 完备生态 Java体系
Envoy 云原生集成 C++扩展

5.3 性能调优要点

  • 共享字典容量预估(1M≈16,000个key)
  • LuaJIT FFI优化热点代码
  • 定时器实现异步日志上报

5.4 安全防护误区

  • 不要依赖单一鉴权方式(JWT+签名双重校验)
  • IP黑白名单需配合UA特征识别
  • 限流阈值设置必须灰度验证

6. 总结与展望

经过实战检验的OpenResty网关方案,在保持C语言级别性能的同时,通过Lua的灵活性实现了:

  • 实时精准的流量清洗
  • 多层防御的安全城墙
  • 自动维护的文档体系

未来演进方向:

  1. 机器学习驱动的动态防护策略
  2. 基于WASM的插件扩展机制
  3. 无缝对接Service Mesh架构