OpenResty 使用示例

发布时间: 更新时间: 总字数:654 阅读时间:2m 作者: 分享 复制网址

OpenResty 使用示例

protocal 转换

  • 示例
location ~ ^/api/([-_a-zA-Z0-9/]+).json {
    access_by_lua_file  /path/to/lua/api/protocal_decode.lua;
    content_by_lua_file /path/to/lua/api/$1.lua;
    body_filter_by_lua_file  /path/to/lua/api/protocal_encode.lua;
}
  • API 设计,添加自己 的 HTTP api 规范地址
    location ~ ^/app/([-_a-zA-Z0-9/]+) {
        set $path $1;
        content_by_lua_file /path/to/lua/app/root/$path.lua;
    }

实现 IP 限制

init_by_lua_block {
  local iputils = require("resty.iputils")
  iputils.enable_lrucache()
  local whitelist_ips = {
      "127.0.0.1",
      "10.10.10.0/24",
      "192.168.0.0/16",
  }

  -- WARNING: Global variable, recommend this is cached at the module level
  -- https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker
  whitelist = iputils.parse_cidrs(whitelist_ips)
}

access_by_lua_block {
    local iputils = require("resty.iputils")
    if not iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist) then
      return ngx.exit(ngx.HTTP_FORBIDDEN)
    end
}
access_by_lua_block {
    if ngx.var.remote_addr == "1.1.1.1" then
        local headers = ngx.req.get_headers()
        for k,v in pairs(headers) do
            ngx.log(ngx.ERR , "header ", k, ": ", v)
        end
        ngx.log(ngx.ERR , "request_body: ", ngx.var.request_body)
    end
}

代理其他API

使用 http 客户端代理 http 请求

  • 安装
opm install pintsized/lua-resty-http
  • 示例代码
    location /test {
        content_by_lua_block {
            ngx.req.read_body()
            local args, err = ngx.req.get_uri_args()

            local http = require "resty.http"
            local httpc = http.new()
            httpc:set_timeout(1000)  -- 1000ms
            -- https://docs.github.com/zh/rest/guides/getting-started-with-the-rest-api?apiVersion=2022-11-28&tool=curl#using-body-parameters
            local res, err = httpc:request_uri("https://api.github.com/repos/octocat/Spoon-Knife/issues", {
                method = "POST",
                body = args.data,
                headers = {
                    ["Accept"] = "Accept",
                    ["Authorization"] = "Bearer YOUR-TOKEN",
                }
            })

            if 200 ~= res.status then
                ngx.exit(res.status)
            end

            if args.key == res.body then
                ngx.say("valid request")
            else
                ngx.say("invalid request")
            end
        }
    }

快速响应终端

ngx.say("xxx")
ngx.eof()
- 下面处理其它逻辑

限速

限速分以下几种

  • limit_rate 限制响应速度
  • limit_conn 限制连接数
  • limit_req 限制请求数

限制响应速度

access_by_lua_block {
    -- 设定当前请求的响应上限是 每秒 300K 字节
    ngx.var.limit_rate = "300K"
}

限制连接数和请求数

需要使用 openresty/lua-resty-limit-traffic

  • nginx.conf
lua_code_cache on;
# 注意 limit_conn_store 的大小需要足够放置限流所需的键值。
# 每个 $binary_remote_addr 大小不会超过 16 字节(IPv6 情况下),算上 lua_shared_dict 的节点大小,总共不到 64 字节。
# 100M 可以放 1.6M 个键值对
lua_shared_dict limit_conn_store 100M;
server {
    listen 8080;
    location / {
        access_by_lua_file src/access.lua;
        content_by_lua_file src/content.lua;
        log_by_lua_file src/log.lua;
    }
}
  • utils/limit_conn.lua
local limit_conn = require "resty.limit.conn"

-- new 的第四个参数用于估算每个请求会维持多长时间,以便于应用漏桶算法
local limit, limit_err = limit_conn.new("limit_conn_store", 10, 2, 0.05)
if not limit then
    error("failed to instantiate a resty.limit.conn object: ", limit_err)
end

local _M = {}

function _M.incoming()
    local key = ngx.var.binary_remote_addr
    local delay, err = limit:incoming(key, true)
    if not delay then
        if err == "rejected" then
            return ngx.exit(503)
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end

    if limit:is_committed() then
        local ctx = ngx.ctx
        ctx.limit_conn_key = key
        ctx.limit_conn_delay = delay
    end

    if delay >= 0.001 then
        ngx.log(ngx.WARN, "delaying conn, excess ", delay,
                "s per binary_remote_addr by limit_conn_store")
        ngx.sleep(delay)
    end
end

function _M.leaving()
    local ctx = ngx.ctx
    local key = ctx.limit_conn_key
    if key then
        local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
        local conn, err = limit:leaving(key, latency)
        if not conn then
            ngx.log(ngx.ERR,
            "failed to record the connection leaving ",
            "request: ", err)
        end
    end
end

return _M
  • src/access.lua
local limit_conn = require "utils.limit_conn"


-- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
if ngx.req.is_internal() then
    return
end
limit_conn.incoming()
  • src/log.lua
local limit_conn = require "utils.limit_conn"
limit_conn.leaving()
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数