一 Nginx加载Lua环境
默认情况下Nginx不支持Lua模块, 需要安装LuaJIT解释器, 并且需要重新编译Nginx
1.环境准备
[root@nginx ~]# yum -y install gcc gcc-c++ make pcre-devel zlib-devel openssl-devel
2.下载最新的luajit和ngx_devel_kit以及lua-nginx-module
[root@nginx ~]# mkdir -p /soft/src && cd /soft/src
[root@nginx ~]# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
[root@nginx ~]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
[root@nginx~]#wget https://github.com/openresty/lua-nginx-module/archive/v0.10.13.tar.gz
3.解压ngx_devel_kit和lua-nginx-module
//解压后为ngx_devel_kit-0.2.19
[root@nginx ~]# tar xf v0.2.19.tar.gz
//解压后为lua-nginx-module-0.9.16
[root@nginx ~]# tar xf v0.10.13.tar.gz
4.安装LuaJIT Luajit是Lua即时编译器。
[root@nginx ~]# tar zxvf LuaJIT-2.0.3.tar.gz
[root@nginx ~]# cd LuaJIT-2.0.3
[root@nginx ~]# make && make install
5.安装Nginx并加载模块(下载对应nginx版本并查看安装模块,在安装模块基础上增加安装的两个模块)
[root@nginx ~]# cd /soft/src
[root@nginx ~]# wget http://nginx.org/download/nginx-1.12.2.tar.gz
[root@nginx ~]# tar xf nginx-1.12.2.tar.gz
[root@nginx~]#
./configure--prefix=/nginx
--add-module=/soft/src/ngx_devel_kit-0.2.19 --add-module=/soft/src/lua-nginx-module-0.10.13
[root@nginx ~]# make -j2 && make install
//建立软链接, 不建立会出现share object错误
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
//4.加载lua库,加入到ld.so.conf文件
echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf
ldconfig
二 lua连接redis
下载redis.lua 放到相应文件夹中,如/usr/local/nginx/lua
并在nginx的http层添加一行
如:/usr/local/nginx/conf/nginx.conf
lua_package_path "/usr/local/nginx/lua/redis.lua";
重启nginx即可
三 添加配置文件
1 /usr/local/nginx/lua 上传写好的access.lua脚本
2 修改www.conf 添加一行
access_by_lua_file /usr/local/nginx/lua/access.lua;
3 重启nginx即可
四 access.lua脚本重点
需修改字段:
1 时间
--禁封ip时间--
ip_bind_time = 60
--ip访问时间频率时间段--
ip_time_out = 30
--ip访问频率最大值--
connect_count = 15
2 redis连接的IP端口密码
3 需要跳转的验证码页面连接
条件:在30s中如果访问超过15次跳转验证码
跳转回原页面:1 滑动验证码 2等待60s后(禁封时间解除)
access.lua脚本
--禁封ip时间--
ip_bind_time = 60
--ip访问世家频率时间段--
ip_time_out = 30
--ip访问频率最大值--
connect_count = 15
-- 禁封时间中,30s内访问50次旧验证码--
--clientIP获取真实IP--
clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
--判断只对详情页生效---
local source1=ngx.var.scheme.."://"..ngx.var.host..ngx.var.request_uri
--local m, err = ngx.re.match(source1, "(auctionListNew|tmallIndexNew|transEnprsNew|qitaIndexNew|shopsGet|auctionGet)-.*\.(html|do|action)")
--source1, err = red:lpush("source1",m)
--正则匹配--
local m, err = ngx.re.match(source1, "(auctionListNew|tmallIndexNew|transEnprsNew|qitaIndexNew|shopsGet|auctionGet)")
--sourice1, err = red:lpush("source1",source1)
if m == nil then
goto B
end
--连接redis--
local redis = require "resty.redis"
local red = redis:new()
local ok, err = red:connect("your redis IP", 6379)
ok, err = red:auth("your passwd")
red:set_timeout(1000)
--local source2=ngx.var.scheme.."://"..ngx.var.host..ngx.var.request_uri
--source2, err = red:lpush("source2",source2)--
--ngx.log(ngx.INFO, " string:", str)
--如果连接不成功直接退出---
if not ok then
goto A
end
--达到条件,跳转验证码页面---
is_bind, err = red:get("bind:"..ngx.var.remote_addr)
if is_bind == '1' then
local source=ngx.encode_base64(ngx.var.scheme.."://"..ngx.var.host..ngx.var.request_uri)
local client=ngx.encode_base64(clientIP)
local dest="验证码url".."?u="..source.."A5PA0"..client
ngx.redirect(dest,302)
goto A
end
--记录开始时间和次数---
start_time, err = red:get("time:"..ngx.var.remote_addr)
ip_count, err = red:get("count:"..ngx.var.remote_addr)
--如果开始时间为空或者时间已经大于禁封时间,redis中记录---
if start_time == ngx.null or os.time() - start_time > ip_time_out then
res, err = red:set("time:"..ngx.var.remote_addr , os.time())
res, err = red:expire("time:"..ngx.var.remote_addr, ip_bind_time)
res, err = red:set("count:"..ngx.var.remote_addr , 1)
res, err = red:expire("count:"..ngx.var.remote_addr, ip_bind_time)
else
ip_count = ip_count + 1
res, err = red:incr("count:"..ngx.var.remote_addr)
if ip_count >= connect_count then
res, err = red:set("bind:"..ngx.var.remote_addr, 1)
res, err = red:expire("bind:"..ngx.var.remote_addr, ip_bind_time)
end
end
::A::
local ok, err = red:close()
::B::
lua连接redis脚本
local sub = string.sub
local byte = string.byte
local tcp = ngx.socket.tcp
local null = ngx.null
local type = type
local pairs = pairs
local unpack = unpack
local setmetatable = setmetatable
local tonumber = tonumber
local tostring = tostring
local rawget = rawget
local select = select
--local error = error
local ok, new_tab = pcall(require, "table.new")
if not ok or type(new_tab) ~= "function" then
new_tab = function (narr, nrec) return {} end
end
local _M = new_tab(0, 55)
_M._VERSION = '0.27'
local common_cmds = {
"get", "set", "mget", "mset",
"del", "incr", "decr", -- Strings
"llen", "lindex", "lpop", "lpush",
"lrange", "linsert", -- Lists
"hexists", "hget", "hset", "hmget",
--[[ "hmset", ]] "hdel", -- Hashes
"smembers", "sismember", "sadd", "srem",
"sdiff", "sinter", "sunion", -- Sets
"zrange", "zrangebyscore", "zrank", "zadd",
"zrem", "zincrby", -- Sorted Sets
"auth", "eval", "expire", "script",
"sort" -- Others
}
local sub_commands = {
"subscribe", "psubscribe"
}
local unsub_commands = {
"unsubscribe", "punsubscribe"
}
local mt = { __index = _M }
function _M.new(self)
local sock, err = tcp()
if not sock then
return nil, err
end
return setmetatable({ _sock = sock, _subscribed = false }, mt)
end
function _M.set_timeout(self, timeout)
local sock = rawget(self, "_sock")
if not sock then
error("not initialized", 2)
return
end
sock:settimeout(timeout)
end
function _M.set_timeouts(self, connect_timeout, send_timeout, read_timeout)
local sock = rawget(self, "_sock")
if not sock then
error("not initialized", 2)
return
end
sock:settimeouts(connect_timeout, send_timeout, read_timeout)
end
function _M.connect(self, host, port_or_opts, opts)
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
local unix
do
local typ = type(host)
if typ ~= "string" then
error("bad argument #1 host: string expected, got " .. typ, 2)
end
if sub(host, 1, 5) == "unix:" then
unix = true
end
if unix then
typ = type(port_or_opts)
if port_or_opts ~= nil and typ ~= "table" then
error("bad argument #2 opts: nil or table expected, got " ..
typ, 2)
end
else
typ = type(port_or_opts)
if typ ~= "number" then
port_or_opts = tonumber(port_or_opts)
if port_or_opts == nil then
error("bad argument #2 port: number expected, got " ..
typ, 2)
end
end
if opts ~= nil then
typ = type(opts)
if typ ~= "table" then
error("bad argument #3 opts: nil or table expected, got " ..
typ, 2)
end
end
end
end
self._subscribed = false
local ok, err
if unix then
ok, err = sock:connect(host, port_or_opts)
opts = port_or_opts
else
ok, err = sock:connect(host, port_or_opts, opts)
end
if not ok then
return ok, err
end
if opts and opts.ssl then
ok, err = sock:sslhandshake(false, opts.server_name, opts.ssl_verify)
if not ok then
return ok, "failed to do ssl handshake: " .. err
end
end
return ok, err
end
function _M.set_keepalive(self, ...)
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
if rawget(self, "_subscribed") then
return nil, "subscribed state"
end
return sock:setkeepalive(...)
end
function _M.get_reused_times(self)
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
return sock:getreusedtimes()
end
local function close(self)
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
return sock:close()
end
_M.close = close
local function _read_reply(self, sock)
local line, err = sock:receive()
if not line then
if err == "timeout" and not rawget(self, "_subscribed") then
sock:close()
end
return nil, err
end
local prefix = byte(line)
if prefix == 36 then -- char '$'
-- print("bulk reply")
local size = tonumber(sub(line, 2))
if size < 0 then
return null
end
local data, err = sock:receive(size)
if not data then
if err == "timeout" then
sock:close()
end
return nil, err
end
local dummy, err = sock:receive(2) -- ignore CRLF
if not dummy then
return nil, err
end
return data
elseif prefix == 43 then -- char '+'
-- print("status reply")
return sub(line, 2)
elseif prefix == 42 then -- char '*'
local n = tonumber(sub(line, 2))
-- print("multi-bulk reply: ", n)
if n < 0 then
return null
end
local vals = new_tab(n, 0)
local nvals = 0
for i = 1, n do
local res, err = _read_reply(self, sock)
if res then
nvals = nvals + 1
vals[nvals] = res
elseif res == nil then
return nil, err
else
-- be a valid redis error value
nvals = nvals + 1
vals[nvals] = {false, err}
end
end
return vals
elseif prefix == 58 then -- char ':'
-- print("integer reply")
return tonumber(sub(line, 2))
elseif prefix == 45 then -- char '-'
-- print("error reply: ", n)
return false, sub(line, 2)
else
-- when `line` is an empty string, `prefix` will be equal to nil.
return nil, "unknown prefix: \"" .. tostring(prefix) .. "\""
end
end
local function _gen_req(args)
local nargs = #args
local req = new_tab(nargs * 5 + 1, 0)
req[1] = "*" .. nargs .. "\r\n"
local nbits = 2
for i = 1, nargs do
local arg = args[i]
if type(arg) ~= "string" then
arg = tostring(arg)
end
req[nbits] = "$"
req[nbits + 1] = #arg
req[nbits + 2] = "\r\n"
req[nbits + 3] = arg
req[nbits + 4] = "\r\n"
nbits = nbits + 5
end
-- it is much faster to do string concatenation on the C land
-- in real world (large number of strings in the Lua VM)
return req
end
local function _do_cmd(self, ...)
local args = {...}
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
local req = _gen_req(args)
local reqs = rawget(self, "_reqs")
if reqs then
reqs[#reqs + 1] = req
return
end
-- print("request: ", table.concat(req))
local bytes, err = sock:send(req)
if not bytes then
return nil, err
end
return _read_reply(self, sock)
end
local function _check_subscribed(self, res)
if type(res) == "table"
and (res[1] == "unsubscribe" or res[1] == "punsubscribe")
and res[3] == 0
then
self._subscribed = false
end
end
function _M.read_reply(self)
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
if not rawget(self, "_subscribed") then
return nil, "not subscribed"
end
local res, err = _read_reply(self, sock)
_check_subscribed(self, res)
return res, err
end
for i = 1, #common_cmds do
local cmd = common_cmds[i]
_M[cmd] =
function (self, ...)
return _do_cmd(self, cmd, ...)
end
end
for i = 1, #sub_commands do
local cmd = sub_commands[i]
_M[cmd] =
function (self, ...)
self._subscribed = true
return _do_cmd(self, cmd, ...)
end
end
for i = 1, #unsub_commands do
local cmd = unsub_commands[i]
_M[cmd] =
function (self, ...)
local res, err = _do_cmd(self, cmd, ...)
_check_subscribed(self, res)
return res, err
end
end
function _M.hmset(self, hashname, ...)
if select('#', ...) == 1 then
local t = select(1, ...)
local n = 0
for k, v in pairs(t) do
n = n + 2
end
local array = new_tab(n, 0)
local i = 0
for k, v in pairs(t) do
array[i + 1] = k
array[i + 2] = v
i = i + 2
end
-- print("key", hashname)
return _do_cmd(self, "hmset", hashname, unpack(array))
end
-- backwards compatibility
return _do_cmd(self, "hmset", hashname, ...)
end
function _M.init_pipeline(self, n)
self._reqs = new_tab(n or 4, 0)
end
function _M.cancel_pipeline(self)
self._reqs = nil
end
function _M.commit_pipeline(self)
local reqs = rawget(self, "_reqs")
if not reqs then
return nil, "no pipeline"
end
self._reqs = nil
local sock = rawget(self, "_sock")
if not sock then
return nil, "not initialized"
end
local bytes, err = sock:send(reqs)
if not bytes then
return nil, err
end
local nvals = 0
local nreqs = #reqs
local vals = new_tab(nreqs, 0)
for i = 1, nreqs do
local res, err = _read_reply(self, sock)
if res then
nvals = nvals + 1
vals[nvals] = res
elseif res == nil then
if err == "timeout" then
close(self)
end
return nil, err
else
-- be a valid redis error value
nvals = nvals + 1
vals[nvals] = {false, err}
end
end
return vals
end
function _M.array_to_hash(self, t)
local n = #t
-- print("n = ", n)
local h = new_tab(0, n / 2)
for i = 1, n, 2 do
h[t[i]] = t[i + 1]
end
return h
end
-- this method is deperate since we already do lazy method generation.
function _M.add_commands(...)
local cmds = {...}
for i = 1, #cmds do
local cmd = cmds[i]
_M[cmd] =
function (self, ...)
return _do_cmd(self, cmd, ...)
end
end
end
setmetatable(_M, {__index = function(self, cmd)
local method =
function (self, ...)
return _do_cmd(self, cmd, ...)
end
-- cache the lazily generated method in our
-- module table
_M[cmd] = method
return method
end})
return _M
网友评论