nginx-openresty实现限流

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, "")





完结