nginx-openresty实现限流
这个没啥说的,比较简单.
NGINX配置
location ~ /lua_request {
#default_type 'text/html';
default_type 'text/json';
content_by_lua_file '/Users/liuhao/my-shell/lua/index.lua';
#content_by_lua_file '/Users/liuhao/my-shell/lua/middle.lua';
}
lua代码
--官方包
local cjson = require("cjson") --json操作
local restyRedis = require("resty.redis")--Redis操作
local redis = restyRedis.new()
--封装Redis
local MyRedis = {db_index=0,use_pool=false}
--redis connect
function MyRedis:connect()
--设置超时(毫秒)
redis:set_timeout(2000)
--建立连接
local ok, err = redis:connect("127.0.0.1", 6379)
if not ok then
self.errMsg("connect",err)
return false
end
-- 如果有密码就用这个local res, err = redis:auth("password")
--连接池状态无法使用库选择
if not self.use_pool then
redis:select(self.db_index)
end
return true
end
--redis get
function MyRedis:get(key)
local resp, err = redis:get(key)
if not resp then
self.close()
self.errMsg("get",err)
return "0"
end
return resp
end
--redis incr
function MyRedis:incr(key)
local ok,err = redis:incr(key)
if not ok then
self.close()
self.errMsg("incr",err)
return false
end
return true
end
--redis setEx
function MyRedis:setEx(key,second,value)
local ok,err = redis:setEx(key,second,value)
if not ok then
self.close()
self.errMsg("setEx",err)
return false
end
return true
end
--redis 关闭连接
function MyRedis:close()
if not self.use_pool then
--普通模式,非连接池
local ok,err = redis:close()
if not ok then
self.errMsg("sample close",err)
return false
end
return
else
--连接池模式
local pool_max_idle_time = 10000 --毫秒
local pool_size = 100 --连接池大小
local ok, err = redis:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
self.errMsg("pool close",err)
return false
end
end
-- 正确返回
return true
end
--错误处理
function MyRedis:errMsg(msg,err)
--打印日志
return ngx.log(ngx.ERR,"MyRedis error the message is:",msg,"---the error is :",err)
end
--获取客户端的IP
local function getClientIP()
--获取客户端的IP
clientIP = ngx.req.get_headers()["X-Real-IP"]
--如果clientIP为空 则从x_forwarded_for获取
if clientIP ==nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
--如果clientIP还为空 则从remote_addr获取
if clientIP ==nil then
clientIP = ngx.var.remote_addr
end
return clientIP
end
--响应客户端
local function responseJson(code, msg)
--拼装返回对象
if code == 0 and msg=="" then
msg="success"
end
if code == 1 and msg=="" then
msg="system error"
end
local reponseObj = {
code = code,
message = msg,
data = {
client_ip=getClientIP(),
},
}
--对象格式化为json, 如果要把json字符串转换为对象,可以用cjson.decode()即可
local responseString = cjson.encode(reponseObj)
ngx.say(responseString)
end
--连接Redis
if not MyRedis:connect() then
return responseJson(1, "")
end
--redis获取数据
local clientIP = "lua-request-"..getClientIP()
local getResp = MyRedis:get(clientIP)
-- 0 != null,Key 不存在时为null(这里的null就是lua的nil)
if getResp == ngx.null then
--Redis添加一条数据
if not MyRedis:setEx(clientIP, 10,1) then
return responseJson(1, "")
end
else
--判断限制
if getResp >= "3" then
return responseJson(1,"too often")
end
--Redis设置数据
if not MyRedis:incr(clientIP) then
return responseJson(1,"")
end
end
--Redis使用完毕,关闭连接
MyRedis:close()
return responseJson(0, "")
完结
来源:oschina
链接:https://my.oschina.net/chinaliuhan/blog/3190016