在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
openresty开发系列37--nginx-lua-redis实现访问频率控制
2)编辑/usr/local/lua/access_by_limit_frequency.lua
local function close_redis(red) if not red then return end --释放连接(连接池实现) local pool_max_idle_time = 10000 --毫秒 local pool_size = 100 --连接池大小 local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) if not ok then ngx.say("set keepalive error : ", err) end end local function errlog(...) ngx.log(ngx.ERR, "redis: ", ...) end local redis = require "resty.redis" --引入redis模块 local red = redis:new() --创建一个对象,注意是用冒号调用的 --设置超时(毫秒) red:set_timeout(1000) --建立连接 local ip = "10.11.0.215" local port = 6379 local ok, err = red:connect(ip, port) if not ok then close_redis(red) errlog("Cannot connect"); return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local key = "limit:frequency:login:"..ngx.var.remote_addr --得到此客户端IP的频次 local resp, err = red:get(key) if not resp then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 获取值失败 end if resp == ngx.null then red:set(key, 1) -- 单位时间 第一次访问 red:expire(key, 10) --10秒时间 过期 end if type(resp) == "string" then if tonumber(resp) > 10 then -- 超过10次 close_redis(red) return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403 end end --调用API设置key ok, err = red:incr(key) if not ok then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 报错 end close_redis(red) # 当redis设置了密码时,需要用red:auth() 方法进行验证 # vim /usr/local/lua/access_by_limit_frequency.lua local function close_redis(red) if not red then return end local pool_max_idle_time = 10000 local pool_size = 100 local ok, err = red:set_keepalive(pool_max_idle_tme, pool_size) if not ok then ngx.say("set keepalive err : ", err) end end local function errlog(...) ngx.log(ngx.ERR, "redis: ", ...) end local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) local ip = "10.11.0.215" local port = 6379 local ok,err = red:connect(ip, port) if not ok then close_redis(red) errlog("connot connect"); return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local count, err = red:get_reused_times() if 0 == count then ----新建连接,需要认证密码 ok, err = red:auth("redis123") if not ok then ngx.say("failed to auth: ", err) return end elseif err then ----从连接池中获取连接,无需再次认证密码 ngx.say("failed to get reused times: ", err) return end local key = "limit:frequency:login: " ..ngx.var.remote_addr --得到此客户端IP的频次 local resp,err = red:get(key) if not resp then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end if resp == ngx.null then red:set(key, 1) red:expire(key, 100) -- 设置过期时间,即返回403的时间为100秒 end --ngx.say("connect ok") --ngx.say("resp:",resp) if type(resp) == "string" then if tonumber(resp) > 10 then close_redis(red) return ngx.exit(ngx.HTTP_FORBIDDEN) end end ok, err = red:incr(key) if not ok then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end close_redis(red) 请求地址:/frequency |
请发表评论