1 Star 0 Fork 50

maolala/lua-limit

forked from haixing/lua-limit 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
limit.lua 5.79 KB
一键复制 编辑 原始数据 按行查看 历史
haixing 提交于 2019-09-19 09:48 . fix word
--[[
通用限流脚本,主控制类
Author: mahaixing@gmail.com
Version: 0.0.1
License: MIT
]]
-- 导入数学模块
local math = require "math"
-- 导入工具类
local utils = require "utils"
local assert = assert
local setmetatable = setmetatable
-- 默认 who 函数
local function default_who(limit)
return true, {rule = "default_rule"}
end
-- 默认 message 函数
local function default_message(limit, data)
ngx.header.content_type = "text/html; charset=utf-8"
ngx.say("#limited#")
ngx.exit(ngx.exit(ngx.HTTP_OK))
end
local _M = {
_VERSION = "0.0.1"
}
--[[
创建新对象
]]
function _M:new(conf)
-- 如果没有传入配置 table,则引入默认的 limit_conf.lua
-- 该文件需要在 package.path 环境变量指向的目录中
if conf == nil then
conf = require "limit_conf"
end
-- 新创建的对象
local object = {
-- 配置文件
conf = conf,
-- http请求参数,包含 GET 和 POST
args = utils.get_url_args(),
-- redis 链接,需要调用 get_redis 方法初始化获得,需要在
-- message方法中关闭
redis = nil,
-- who 指向的方法,用于确定限流目标
-- who 指向的可以是 function 也可以是包含 function 的 table
-- message 方法,用于输出
funcs = {
who = default_who,
message = default_message
}
}
self.__index = self
return setmetatable(object, self)
end
--[[
执行跳转,根据请求头 ACCETP 部分,如果是 json 则序列化data
否则跳转到 page_path
]]
function _M:redirect(page_path, data)
utils.send_redirect(page_path, data)
end
--[[
初始化redis链接,redis链接在 config.redis 中配置
返回 nil 说明配置文件中没有配置 redis 参数,或者初
始化 redis 错误
]]
function _M:get_redis()
-- 如果没有配置 redis 参数,则返回nil
if self.conf["redis"] == nil then return nil end
-- 如果初始化过了,则返回现有实例(需要考虑被关闭情况)
if self.redis ~= nil then return self.redis end
local host = assert(self.conf["redis"]["host"])
local port = assert(self.conf["redis"]["port"])
local auth = self.conf["redis"]["auth"]
local timeout = 500
if self.conf["redis"]["timeout"] ~= nil then
local timeout = self.conf["redis"]["timeout"]
end
-- 导入redis模块
self.redis = require "resty.redis":new()
self.redis:set_timeout(timeout)
local ok, err = self.redis:connect(host, port)
if auth ~= nil then
self.redis:auth(auth)
end
if not ok then
utils.log("connect to redis failed: " .. err, ngx.ERR)
error("connect to redis failed: " .. err)
end
return self.redis
end
--[[
执行 who 可以指向:
1. function
2、包含一系列 function 的 table
3. nil,如果这种情况会使用默认的键名 default_rule
function 方法返回 2 个值:
1. boolean 用于确定当前是否是该方法关心的限流对象
2. table
result: 必填,返回结果 true false
rule: 非必填,如不提供则使用默认规则
data: 非必填,如不提供则不处理,如提供则可在 message 函数中处理
当某一个function 返回 true 后,
]]
function _M:who(funcs)
if funcs ~= nil then
self.funcs.who = funcs
end
return self
end
-- 执行 who 函数
function _M:process_who()
local result, rule
if (type(self.funcs.who) == "table") then
for _, func in pairs(self.funcs.who) do
result, extra = func(self)
if result then break end
end
elseif (type(self.funcs.who) == "function") then
result, extra = self.funcs.who(self)
end
return result, extra
end
-- 执行 message 函数
function _M:process_message(data)
self.funcs.message(self, data)
end
-- 获取 who 函数返回的限流规则
function _M:process_rule(rule)
self.rule = self.conf[rule]
if self.rule == nil then
error("returned rule does not exist!")
utils.log("returned rule does not exist!", ngx.ERR)
end
end
-- 执行限流动作
function _M:execute()
-- 执行 who 函数,返回:
-- 1. 是否是限流目标 boolean 2. 适用的限流规则 3. 可能的数据如果message函数需要处理的话
local who_result, extra = self:process_who()
-- 如果所有的 who 函数都返回 false 说明这个请求不是要限流的目标,直接放行
if (not who_result) then
return
end
if (extra.rule ~= nil) then
-- 拿到限流规则
self:process_rule(extra.rule)
utils.log("use rule: " .. extra.rule, ngx.INFO)
end
if (extra.message ~= nil) then
self.message = extra.message
end
-- see_next 是用来确定限流规则是否需要参考限流链的下一个规则。
local result = true, see_next
-- 循环执行限流规则
for limiter_name, limiter_conf in pairs(self.rule) do
-- 包含限流规则 lua 文件
local limiter = require("limiters." .. limiter_name)
-- 执行限流
local instance = limiter:new(limiter_conf)
instance:process_config()
result, see_next = instance:execute()
-- 如果限流返回 true 则说明此链接已被此规则限流
-- 如果 see_next 返回 true 则说明需要参考限流链的吓一条限流规则
-- 否则不执行限流链的后面一条规则,跳出循环
if (see_next == nil) then see_next = false end
if (result == true) or (see_next == false) then
break
end
end
-- 返回到客户浏览器
if result then
self:process_message(extra.data)
end
end
return _M
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Lua
1
https://gitee.com/maolala/lua-limit.git
git@gitee.com:maolala/lua-limit.git
maolala
lua-limit
lua-limit
master

搜索帮助