Lua 是由巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于1993年开发的一种轻量、小巧的脚本语言,用标准 C 语言编写,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
lua官网:http://www.lua.org/
Lua/luajit/nginx/openresty关系,lua是脚本语言,luajit是lua的功能包与解析器(相当于java对应的jdk),nginx可以内嵌luajit(承载的容器),openresty把额外扩展包集成到nginx里(相当于spring脚手架)
windows版lua下载
http://joedf.ahkscript.org/LuaBuilds/
http://luabinaries.sourceforge.net/
EmmyLua插件
https://github.com/EmmyLua/IntelliJ-EmmyLua
https://emmylua.github.io/zh_CN/
LDT 基于eclipse
https://www.eclipse.org/ldt/
保留关键字
and/break/do/else/elseif/end/false/for/function if/in/local/nil/not/or/repeat/return/then/true/until/while
注释
-- 两个减号是行注释
--[[
这是块注释
这是块注释.
--]]
Lua的数字只有double型,64bits
-- 可以以如下的方式表示数字
num = 1024
num = 3.0
num = 3.1416
num = 314.16e-2
num = 0.31416E1
num = 0xff
num = 0x56
可以用单引号,也可以用双引号,也可以使用转义字符’\n’(换行),‘\r’(回车), ‘\t’ (横向制表),‘\v’(纵向制表),‘’(反斜杠),‘"’(双引号), 以及’‘’(单引号)等等
下面的四种方式定义了完全相同的字符串(其中的两个中括号可以用于定义有换行的字符串)
--[[ 输出alo
123"]]
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
C语言中的NULL在Lua中是nil,比如你访问一个没有声明过的变量,就是nil
只有nil和false是 false;数字0,‘’ 空字符串(‘\0’)都是true
lua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里。
变量前加local关键字的是局部变量
local i = 0
local max = 10
while i <= max do
print(i)
i = i +1
end
local function main()
local age = 140
local sex = 'Male'
if age == 40 and sex =="Male" then
print(" 男人四十一枝花 ")
elseif age > 60 and sex ~="Female" then
print("old man!!")
elseif age < 20 then
io.write("too young, too simple!\n")
else
print("Your age is "..age)
end
end
-- 调用
main()
sum = 0
for i = 100, 1, -2 do
sum = sum + i
end
-- ==========================第一个=============
function myPower(x,y)
return y+x
end
power2 = myPower(2,3)
print(power2)
-- ==========================第二个=============
function newCounter()
local i = 0
return function() -- anonymous function
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
print(c1())
name, age,bGay = "shawn", 37, false, "[email protected]"
print(name,age,bGay)
function isMyGirl(name)
return name == 'lucy' , name
end
local bol,name = isMyGirl('lucy')
-- lucy true
print(name,bol)
key,value的键值对 类似 map
local function main()
dog = {name='shawn',age=18,height=165.5}
dog.age=22
print(dog.name,dog.age,dog.height)
print(dog)
end
main()
local function main()
arr = {"string", 100, "dog",function() print("wangwang!") return 1 end}
print(arr[4]())
end
main()
-- 遍历数组
for k, v in pairs(arr) do
print(k, v)
end
local function main()
person = {name='旺财',age = 18}
function person.eat(food)
print(person.name .." eating "..food)
end
person.eat("骨头")
end
main()
OpenResty通过汇聚各种设计精良的Nginx模块(主要由OpenResty团队自主开发)将Nginx变成一个强大的通用Web应用平台。这样,Web开发人员和系统工程师可以使用Lua脚本语言调动Nginx支持的各种C以及Lua模块,快速构造出足以胜任10KB乃至1000KB以上单机并发连接的高性能Web应用系统。
OpenResty的目标是让Web服务直接跑在Nginx服务内部,充分利用Nginx的非阻塞I/O模型,不仅对HTTP客户端请求,甚至对远程后端(如MySQL、PostgreSQL、Memcached以及Redis等)都进行一致的高性能响应。
参考:一文带你详解Nginx/OpenResty
执行原理
OpenResty中,每个Worker进程使用一个Lua VM(Lua虚拟机),当请求被分配到Worker时,将在这个Lua VM中创建一个协程,协程之间数据隔离,每个协程都具有独立的全局变量。
ngx_lua是将Lua嵌入Nginx,让Nginx执行Lua脚本,并且高并发、非阻塞地处理各种请求。Lua内置协程可以很好地将异步回调转换成顺序调用的形式。ngx_lua在Lua中进行的IO操作都会委托给Nginx的事件模型,从而实现非阻塞调用。开发者可以采用串行的方式编写程序,ngx_lua会在进行阻塞的IO操作时自动中断,保存上下文,然后将IO操作委托给Nginx事件处理机制,在IO操作完成后,ngx_lua会恢复上下文,程序继续执行,这些操作对用户程序都是透明的。
每个Nginx的Worker进程持有一个Lua解释器或LuaJIT实例,被这个Worker处理的所有请求共享这个实例。每个请求的context上下文会被Lua轻量级的协程分隔,从而保证各个请求是独立的
预编译安装
http://openresty.org/cn/linux-packages.html
# 服务命令
service openresty start
service openresty stop
nginx -t
service openresty reload
nginx -V
源码编译安装
http://openresty.org/cn/download.html
# 最小版本基于nginx1.21
wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
# 该包包含有gcc,g ++ 和 make
apt install build-essential
tar -zxvf openresty-1.21.4.1.tar.gz
cd openresty-1.21.4.1
# Centos
yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
# ubuntu
sudo apt install zlib1g
sudo apt install zlib1g-dev
sudo apt-get install libpcre3-dev
sudo apt-get install libssl-dev
# 默认, --prefix=/usr/local/openresty 程序会被安装到usr/local/openresty目录
./configure
# 可以指定各种选项
./configure --prefix=/opt/openresty \
--with-luajit \
--without-http_redis2_module \
--with-http_iconv_module \
--with-http_postgres_module
# 帮助
./configure --help
# 编译与安装
make && make install
测试lua脚本
此时的nginx和配置文件都是openresty包提供的
# 在Nginx.conf 中写入
location /lua {
default_type text/html;
content_by_lua 'ngx.say("Hello, World!
")';
}
location /lua {
default_type text/html;
# 创建外部脚本,脚本内容ngx.say("Hello, World!
")
content_by_lua_file conf/lua/hello.lua;
}
github官方文档:https://github.com/openresty/lua-nginx-module#readme
wiki文档:https://www.nginx.com/resources/wiki/modules/lua/
文档:https://openresty-reference.readthedocs.io/en/latest/
# 设置包含的lua文件块
include /etc/nginx/conf.d/lua.conf;
# lua.conf配置文件
server {
listen 80;
server_name localhost;
location /lua {
# 热部署,hello.lua改变即可实时刷新,无需重启
lua_code_cache off;
default_type text/html;
content_by_lua_file /etc/nginx/conf.d/hello.lua;
}
}
修改nginx变量
修改uri
访问控制
修改响应头
修改响应体
日志
local uri_args = ngx.req.get_uri_args()
for k, v in pairs(uri_args) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ", "), "
")
else
ngx.say(k, ": ", v, "
")
end
end
local headers = ngx.req.get_headers()
ngx.say("Host : ", headers["Host"], "
")
ngx.say("user-agent : ", headers["user-agent"], "
")
ngx.say("user-agent : ", headers.user_agent, "
")
for k,v in pairs(headers) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ","), "
")
else
ngx.say(k, " : ", v, "
")
end
end
ngx.req.read_body()
ngx.say("post args begin", "
")
local post_args = ngx.req.get_post_args()
for k, v in pairs(post_args) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ", "), "
")
else
ngx.say(k, ": ", v, "
")
end
end
-- http协议版本
ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "
")
-- 请求方法
ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "
")
-- 原始的请求头内容
ngx.say("ngx.req.raw_header : ", ngx.req.raw_header(), "
")
-- body内容体
ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "
")
ngx常用用法,例如
say
print可以作为content返回,redirect
可以实现跳转,ngx.location.capture
可以请求一个url,一般是内部url。exit
可以返回状态码,shared
可以作为一个所有进程共享的缓存kv池。
log
ngx.log(ngx.INFO, “日志内容”) 。级别有ngx.STDERR/ngx.EMERG /ngx.ALERT/ ngx.CRIT /ngx.ERR /ngx.WARN/ ngx.NOTICE/ ngx.INFO /ngx.DEBUG
var与ctx
ngx.var
可以获取或者修改nginx上下文的$xx变量,包括内置的变量,和在location范围内set的变量。nginx上下文的变量参考
一个request上下文的ngx.ctx是一个table可以自由的赋值和获取。例如rewrite_by_lua中ngx.ctx.a=10, content_by_lua中能拿到ngx.ctx.a
location.capture
local res = ngx.location.capture('/foo?a=1&b=3&c=%3a') -- get请求, res有status body header和truncated属性
ngx.req.set_header("Content-Type", "application/json")
ngx.location.capture('/foo/bar',{ method = ngx.HTTP_POST, body = cjson.encode({a = 'hello, world' })) --post
req
hash与编码
re正则
os相关的
# 其中#注释掉的可以在需要的时候开启并修改,没有注释掉的(除了下面location示例)不要删掉,基本都是必须的配置项。
###############################第一部分 全局配置############################
#user nobody; 指定启动进程的用户,默认不用指定即可。
#error_log logs/error.log; 配置日志输出,虽然叫error_log但是可以定义输出的级别,默认不写是ERROR级别
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid; 记录pid的文件,默认就是放到这个位置,可以修改。
# 只启动一个进程,nginx是多进程单线程模型,但是使用了epoll sendfile 非阻塞io
worker_processes 1;
###############################第二部分 event配置############################
#主要是网络连接相关的配置
events {
# 每个worker能连接1024个链接
worker_connections 1024;
#use epoll; 事件驱动模型select|poll|kqueue|epoll|resig
}
###############################第三部分 http配置############################
http {
include mime.types; #文件扩展名与文件类型映射表
default_type text/html; #默认的返回类型,可以在server.location里面改
sendfile on; #开启sendfile系统调用
keepalive_timeout 65; #连接超时时间65s
server {
listen 80;
# 下面展示多个demo,demo之间互相没有依赖关系,可以单独配置来进行测试。
# 其中demo1到demo6 是nginx相关的。
## demo1 展示location路径的不同写法优先级 #################
# =最高优先级 表示路径完全等于,可以匹配/demo1/a/b的请求
location =/demo1/a/b {
echo "=/demo1/a/b";
}
# ^~第二高 表示startsWith,可以匹配/demo1/a/b/c和/demo1/abc请求
location ^~/demo1/a {
echo "^~/demo1/a";
}
# ~等四个符号第三高 表示正则,如果要用{}是特殊符号,需要整个加引号,建议直接加双引号,防止出错,可以匹配/demo1/bcd
# 其他三个:~*不区分大小写正则,!~正则不匹配的,!~*不分大小写的正则不匹配
location "~/demo1/\w{3}$" {
echo "regex";
}
# 最低 没有前置符号 /demo1 /demo111 /demo1/b/c 不符合上面三种,就会匹配到这
location /demo1{
echo "/demo1";
}
### demo2 展示serve静态文件夹 ###############
location / {
root html; # root就是根目录是当前html目录
index index.html index.htm; # index表示默认不写的时候转到的文件
}
## demo3 指定错误文件 ###############
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
## demo4 rewrite重写url rewrite也可以是server级别 ####################
location /demo4 {
# 一般放到最后一行
rewrite ^/(.*) /$1/api permanent; # permanent301, redirect302, break不在匹配后面rewrite规则,last继续向下匹配。
}
##### demo5 demo6 proxy_pass反向代理 ####################
# /demo5 => baidu.com/demo5
# /demo5/a/b => baidu.com/demo5/a/b
location /demo5 {
proxy_pass https://www.baidu.com;
}
# /demo6 => baidu.com
# /demo6/a/b => baidu.com/a/b
location /demo6 {
# proxy_set_header Host $http_host; 如果有请求头改动的需求可以搜索proxy_set_header去了解
proxy_pass https://www.baidu.com/;
}
}
# 下面demo7到demo11是openresty lua的一些配置demo
server {
listen 81;
###### demo7 init_by_lua_block 用来加载经常用到的库 或者 用来对多进程shared变量赋值 ####################
init_by_lua_block {
cjson = require("cjson") --后续的lua流程中可以直接使用cjson
local myname = ngx.shared.info --可以认为是静态变量,通过info:get获取变量值
info:set("name", "frank")
info:set("age", 77)
}
##### demo8 demo9 rewrite_by_lua_block 配合ngx.redirect用来替换rewrite指令 ####################
# 注意rewrite_by_lua和因为作用阶段是nginx原生rewrite之后,所以容易和原生一起用的时候出错,最好的方式就是只用lua的不要用nginx的了。
location /demo8 {
set $a 1;
set $b "";
rewrite_by_lua_block {
ngx.var.b = tonumber(ngx.var.a) + 1
if tonumber(ngx.var.b) == 2 then
return ngx.redirect("/demo9") --默认是302,如果要301或307可以再加一个第二参数即可
end
}
echo "demo8"; # 注意echo是content阶段的,rewrite阶段重定向了请求,就走不到这里了
}
location /demo9 {
echo "demo9";
}
##### demo10 access_by_lua_block 用来做一些加载内容前的准备工作例如访问redis看看用户身份是不是合法 ip是不是合法等 ####################
location /demo10 {
access_by_lua_block {
local res = ngx.location.capture("/auth") -- ngx.location.capture是作为客户端发起http请求拿到结果
if res.status == ngx.HTTP_OK then
return -- 正常return就能走到content阶段
end
if res.status == ngx.HTTP_FORBIDDEN then
ngx.exit(res.status) -- exit + 状态码 就直接返回状态码了
end
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
}
echo "demo10"; # 如果合法的话就返回demo10字样
}
location /auth {
return 200; # 换成403 or 500试试
}
#### demo10 content_by_lua_block 用来作为content阶段的脚本,一般测试用的多 ####################
#不要和 echo proxy_pass等content阶段指令一起用
location /demo10 {
content_by_lua_block{
ngx.say("/demo10");
ngx.say("/demo11"); -- 和外部用俩echo效果类似。ngx.say ngx.print区别是前者会多个回车在最后
}
# echo "echo10"; 如果外面用了echo,则只有echo的效果
# proxy_pass http://www.baidu.com; 如果外面用了proxy_pass也是只有proxy_pass效果了,因为都是content阶段,content只能一个生效。
}
##### demo11 rewrite_by_lua与proxy_pass配合 根据参数进行转发 ####################
location /demo11 {
default_type text/html;
set $proxy "";
rewrite_by_lua ' # 千万别用content,因为content和proxy_pass阶段犯冲
local h = ngx.var.host # 这里从host中提出第一个.之前的部分看是不是a来决定转发到哪
local dot = h:find("%.")
local prefix = h:sub(1,dot-1)
if prefix == "a" then
ngx.var.proxy="127.0.0.1:3000"
else
ngx.var.proxy="127.0.0.1:5500"
end
';
proxy_pass http://$proxy$uri;
}
}
}
lua_shared_dict shared_data 1m;
该配置文件配置在nginx.conf下的http模块,全局共享,会产生锁,是线程安全的
local shared_data = ngx.shared.shared_data
local i = shared_data:get("i")
if not i then
i = 1
shared_data:set("i", i)
ngx.say("lazy set i ", i, "
")
end
i = shared_data:incr("i", 1)
ngx.say("i=", i, "
")
Lua 实现的一个简单的 LRU 缓存,适合在 Lua 空间里直接缓存较为复杂的 Lua 数据结构:它相比 ngx_lua 共享内存字典可以省去较昂贵的序列化操作,相比 memcached 这样的外部服务又能省去较昂贵的 socket 操作
官方文档:https://github.com/openresty/lua-resty-lrucache
# 引用lua文件,会调用cache.lua
# 需要关闭热部署
content_by_lua_block {
require("my/cache").go()
}
自定义函数,放在lualib/my/cache.lua
local _M = {}
-- 这是默认存在的工具包
lrucache = require "resty.lrucache"
-- 需要关闭热部署,这行代码只能执行一次
c, err = lrucache.new(200) -- allow up to 200 items in the cache
ngx.say("count=init")
if not c then
error("failed to create the cache: " .. (err or "unknown"))
end
function _M.go()
count = c:get("count")
c:set("count",100)
ngx.say("count=", count, " --
")
if not count then
c:set("count",1)
ngx.say("lazy set count ", c:get("count"), "
")
else
c:set("count",count+1)
ngx.say("count=", count, "
")
end
end
return _M
参考文档:https://github.com/openresty/lua-resty-redis
使用和redis2-nginx-module差不多,一个是通过lua直接操作
参考文档:https://github.com/openresty/lua-resty-mysql
不推荐带参数
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.say("failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000) -- 1 sec
local ok, err, errcode, sqlstate = db:connect{
host = "192.168.44.211",
port = 3306,
database = "test",
user = "root",
password = "root",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
ngx.say("connected to mysql.
")
local res, err, errcode, sqlstate = db:query("drop table if exists cats")
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
res, err, errcode, sqlstate =
db:query("create table cats "
.. "(id serial primary key, "
.. "name varchar(5))")
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
ngx.say("table cats created.")
res, err, errcode, sqlstate =
db:query("select * from t_emp")
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
local cjson = require "cjson"
ngx.say("result: ", cjson.encode(res))
local ok, err = db:set_keepalive(10000, 100)
if not ok then
ngx.say("failed to set keepalive: ", err)
return
end
参考文档:https://github.com/bungle/lua-resty-template
lua-resty-template模板引擎可以认为是JSP,其最终会被翻译成Lua代码,然后通过ngx.print输出。
安装的话首先需要下载包,然后将里面的template.lua
和template
放在lualib/resty
下
基础语法
{(include_file)}:包含另一个模板文件;
{* var *}:变量输出;
{{ var }}:变量转义输出;
{% code %}:代码片段;
{# comment #}:注释;
{-raw-}:中间的内容不会解析,作为纯文本输出;
nginx.conf进行配置
server {
listen 80;
server_name localhost;
location /lua {
lua_code_cache off;
default_type text/html;
# 模板文件存放位置
set $template_root /etc/nginx/conf.d/template;
# lua文件保存位置
content_by_lua_file /etc/nginx/conf.d/hello.lua;
}
}
模板文件
DOCTYPE html>
<html>
<body>
<h1>name:{{name}}h1>
<h1>age:{{age}}h1>
body>
html>
lua文件
local template = require("resty.template")
local context = {
name = "lucy",
age = 50,
}
template.render("view.html", context)
模板
{(header.html)}
<body>
{# 不转义变量输出 #}
姓名:{* string.upper(name) *}<br/>
{# 转义变量输出 #}
简介:{{description}}
简介:{* description *}<br/>
{# 可以做一些运算 #}
年龄: {* age + 10 *}<br/>
{# 循环输出 #}
爱好:
{% for i, v in ipairs(hobby) do %}
{% if v == '电影' then %} - xxoo
{%else%} - {* v *}
{% end %}
{% end %}<br/>
成绩:
{% local i = 1; %}
{% for k, v in pairs(score) do %}
{% if i > 1 then %},{% end %}
{* k *} = {* v *}
{% i = i + 1 %}
{% end %}<br/>
成绩2:
{% for i = 1, #score2 do local t = score2[i] %}
{% if i > 1 then %},{% end %}
{* t.name *} = {* t.score *}
{% end %}<br/>
{# 中间内容不解析 #}
{-raw-}{(file)}{-raw-}
{(footer.html)}
lua文件
local template = require("resty.template")
template.caching(false)
local context = {
title = "测试",
name = "lucy",
description = "",
age = 40,
hobby = {"电影", "音乐", "阅读"},
score = {语文 = 90, 数学 = 80, 英语 = 70},
score2 = {
{name = "语文", score = 90},
{name = "数学", score = 80},
{name = "英语", score = 70},
}
}
template.render("view.html", context)
模板缓存:默认开启,开发环境可以手动关闭template.caching(true)
模板文件需要业务系统更新与维护,当模板文件更新后,可以通过模板版本号或消息通知Openresty清空缓存重载模板到内存中template.cache = {}
模板
{(header.html)}
<body>
{# 不转义变量输出 #}
姓名:{* string.upper(name) *}<br/>
{# 转义变量输出 #}
年龄: {* age + 10 *}<br/>
{# 循环输出 #}
爱好:
{% for i, v in ipairs(hobby) do %}
{% if v == '电影' then %} - xxoo
{%else%} - {* v *}
{% end %}
{% end %}<br/>
成绩:
{% local i = 1; %}
{% for k, v in pairs(score) do %}
{% if i > 1 then %},{% end %}
{* k *} = {* v *}
{% i = i + 1 %}
{% end %}<br/>
成绩2:
{% for i = 1, #score2 do local t = score2[i] %}
{% if i > 1 then %},{% end %}
{* t.name *} = {* t.score *}
{% end %}<br/>
{# 中间内容不解析 #}
{-raw-}{(file)}{-raw-}
掌门:
{* zhangmen *}
{% for i = 1, #zhangmen do local z = zhangmen[i] %}
{* z.deptId *},{* z.age *},{* z.name *},{* z.empno *},<br>
{% end %}<br/>
{(footer.html)}
lua文件
cjson = require "cjson"
sql="select * from t_emp"
local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000) -- 1 sec
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local res, err = red:get(sql)
if not res then
ngx.say("failed to get sql: ", err)
return
end
if res == ngx.null then
ngx.say("sql"..sql.." not found.")
--mysql查询
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.say("failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000) -- 1 sec
local ok, err, errcode, sqlstate = db:connect{
host = "192.168.44.211",
port = 3306,
database = "zhangmen",
user = "root",
password = "111111",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
ngx.say("connected to mysql.
")
res, err, errcode, sqlstate =
db:query(sql)
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
--ngx.say("result: ", cjson.encode(res))
ok, err = red:set(sql, cjson.encode(res))
if not ok then
ngx.say("failed to set sql: ", err)
return
end
ngx.say("set result: ", ok)
return
end
local template = require("resty.template")
template.caching(false)
local context = {
title = "测试",
name = "lucy",
description = "",
age = 40,
hobby = {"电影", "音乐", "阅读"},
score = {语文 = 90, 数学 = 80, 英语 = 70},
score2 = {
{name = "语文", score = 90},
{name = "数学", score = 80},
{name = "英语", score = 70},
},
zhangmen=cjson.decode(res)
}
template.render("view.html", context)
https://github.com/unixhot/waf
https://github.com/loveshell/ngx_lua_waf
优势
防止 SQL 注入,本地包含,部分溢出,fuzzing 测试,XSS/SSRF 等 Web 攻击
防止 Apache Bench 之类压力测试工具的攻击
屏蔽常见的扫描黑客工具,扫描器
屏蔽图片附件类目录执行权限、防止 webshell 上传
支持 IP 白名单和黑名单功能,直接将黑名单的 IP 访问拒绝
支持 URL 白名单,将不需要过滤的 URL 进行定义
支持 User-Agent 的过滤、支持 CC 攻击防护、限制单个 URL 指定时间的访问次数
支持支持 Cookie 过滤,URL 与 URL 参数过滤
支持日志记录,将所有拒绝的操作,记录到日志中去
https://konghq.com/
https://github.com/kong/kong
Kong 基于 OpenResty,是一个云原生、快速、可扩展、分布式的微服务抽象层(Microservice Abstraction Layer),也叫 API 网关(API Gateway),在 Service Mesh 里也叫 API 中间件(API Middleware)。Kong 开源于 2015 年,核心价值在于高性能和扩展性。从全球 5000 强的组织统计数据来看,Kong 是现在依然在维护的,在生产环境使用最广泛的 API 网关。Kong 宣称自己是世界上最流行的开源微服务 API 网关(The World’s Most Popular Open Source Microservice API Gateway)。
可扩展:可以方便的通过添加节点水平扩展,这意味着可以在很低的延迟下支持很大的系统负载。
模块化:可以通过添加新的插件来扩展 Kong 的能力,这些插件可以通过 RESTful Admin API 来安装和配置。
在任何基础架构上运行:Kong 可以在任何地方都能运行,比如在云或混合环境中部署 Kong,单个或全球的数据中心。
https://github.com/CNSRE/ABTestingGateway
ABTestingGateway 是一个可以动态设置分流策略的网关,关注与灰度发布相关领域,基于 Nginx 和 ngx-lua 开发,使用 Redis 作为分流策略数据库,可以实现动态调度功能。
ABTestingGateway 是新浪微博内部的动态路由系统 dygateway 的一部分,目前已经开源。在以往的基于 Nginx 实现的灰度系统中,分流逻辑往往通过 rewrite 阶段的 if 和 rewrite 指令等实现,优点是性能较高,缺点是功能受限、容易出错,以及转发规则固定,只能静态分流。ABTestingGateway 则采用 ngx-lua,通过启用 lua-shared-dict 和 lua-resty-lock 作为系统缓存和缓存锁,系统获得了较为接近原生 Nginx 转发的性能。
支持多种分流方式,目前包括 iprange、uidrange、uid 尾数和指定uid分流
支持多级分流,动态设置分流策略,即时生效,无需重启
可扩展性,提供了开发框架,开发者可以灵活添加新的分流方式,实现二次开发
高性能,压测数据接近原生 Nginx 转发
灰度系统配置写在 Nginx 配置文件中,方便管理员配置
适用于多种场景:灰度发布、AB 测试和负载均衡等