用nginx_lua根据post内容进行过滤

需求是现在有些post请求的内容导致我们某个应用压力巨大,而正常是同样post的内容在24小时内只会请求一次。 初步思路就是将post内容里的变量部分写入到redis中,然后设置过期时间为1天。这样每次post的时候先查一下redis是否存在这个key。有就直接转到google上,没有就继续proxy_pass。 这里面会有几个坑。 不过lua我是第一次写,所以很多问题都没有提前预计到,测试的时候发生了很多问题。 首先自然是加入nginx-lua-redis模块支持。这里碰到个问题,ngx.say以后要是不加return就会报错。然后模块在应用的时候也要注意一下。

1
lua_package_path "/etc/nginx/lua/lua-resty-redis/lib/?.lua;;"; 

自己写一个lua模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
local redis = require "resty.redis"
local cache = redis.new()
local ok, err = cache.connect(cache, '127.0.0.1', '6379')
ngx.req.read_body()
local method = ngx.var.request_method

cache:set_timeout(60000)

if not ok then
-- ngx.say("failed to connect:", err)
return
end

if method == 'POST' then
local data = ngx.req.get_body_data()
if data then
local i = ngx.re.match(data, "[0-9]{11}")
local phone = i[0]
local exist = cache:exists(phone)
if exist == 0 then
cache:set(phone, "phone")
cache:expire(phone, 86400)
else
ngx.redirect("http://www.google.com", 302)
ngx.say(phone, ' is in baned')
return ngx.exit(403)
-- ngx.say(phone, ' is in baned')
-- return ngx.exit(403)
end
end
end


local ok, err = cache:close()

if not ok then
-- ngx.say("failed to close:", err)
return
end

在location中进行应用。这里要用access_lua_by_file, 而不是 content_lua_by_file。但是用access_lua_by_file的时候必须要retrun好,如果return 200的话会继续proxy_pass, 其他的就直接返回了。

1
2
3
4
location = /VerifyCode { 
access_by_lua_file /etc/nginx/conf.d/include/ban-phone-number.lua;
proxy_pass http://test;
}