APISIX简介
APISIX 为国内知名的开源API 网关产品,国内使用者众多,社区在国内活跃度也非常的高。其开源公司支流科技在国内做开源和定制化产品也是较为成熟的一家科技公司。
APISIX 本身提供了丰富的插件和dashboard 支持,可以用界面管理APISIX的配置,在不复杂的场景下能满足大部分客户的需求。同时APISIX提供了Ingress Controller 能够使用部分自带插件,满足客户在Kubernetes 上面运行的需求。
APISIX 与Kong 定制化差异
在APISIX 诞生之前社区最活跃的OpenResty 定制化方案应该是Kong ,从本质上面来将两者都是基于OpenResty 的定制化方案API 网关,差别在于Kong默认所有的功能都使用Lua 进行开发,APISIX 部分功能使用了C语言做定制化开发(例如:路由功能),所以性能上面APISIX 要比Kong 强上少许,其他方面功能上两者基本没有差别,而且两者都支持插件开发和外部扩展插件。在定制插件管控方式上面,kong 默认开放admin 端口给自定义插件使用,而APISIX 的Admin API 只能是由APISIX 的内置功能使用,自定义插件则需要新开端口 使用Control API。
APISIX架构
可以看到官方的架构在控制面使用AdminAPI 进行插件和功能的配置。但是在某些场景下,我们需要对于网关进行扩展,满足我们私有的定制化序需求,比如我在线上需要动态的判断某个业务的某个版本需要进行灰度,当判断upstream 为指定的后端服务的时候需要添加指定的HEADER 来染色当前的请求,后端做区分,目前这种功能没有通用的插件支持, 需要定制化开发。
目前APISIX 支持全局插件和单个路由插件配置。全局插件可以在没有找到路由的情况下启用,单个路由插件必须在查询到路由规则后才能筛选使用。
Control API
Control API 可以动态为自定义插件配置配置数据,最终能达到的功能是,在一个通用插件动态的绑定数据,不用重新配置路由绑定规则,适合大规模企业应用的数据配置
APISIX 官方在控制面提供了2个API 方式,官方自带的功能都是通过AdminAPI 进行调用配置的,同时官方对于自定义插件提供了Control API 功能。
默认Control API 功能不支持路径参数,只支持 路径 方法 进行路由选择,官方demo 如下:
function _M.control_api()
return {
{
methods = {"GET"},
uris = {"/v1/plugin/example-plugin/hello"},
handler = hello,
}
}
end
上面的代码段需要定义到插件中方能生效。
我们在使用的时候如果需要支持请求PATH 支持参数需要修改apisix.yml 的配置,需要修改的配置如下:
enable_control: true # 开启control API
control:
ip: 127.0.0.1 # control api绑定ip 默认只有本地可以访问
port: 9090 # control api 端口号
router: radixtree_uri_with_parameter # 配置允许 url 路径包含参数
开启后我们就可以正常的使用路径参数了,如我们可以定义 /v1/plugin/test/:test/aaa 这种路由,那么在Control API 内我们怎么在handler 方法取到参数呢?默认APISIX 的路由匹匹配到当前的url ,当我进入定义的handler方法的时候,我们需要重新使用radixtree 这个路由库去重新匹配一下,代码如下:
local rx = radix.new({
{
hosts = { "*" },
methods = { "GET", "POST", "PUT", "PATCH", "DELETE" },
paths = {
"/v1/plugin/test",
"/v1/plugin/test/:test1/aaa",
},
metadata = "metadata /test",
}
})
local function validate_uri()
local uri = ngx.var.uri
local host = ngx.var.host
local opts = {
host = host,
method = ngx.req.get_method(),
matched = {}
}
local route_metadata = rx:match(uri, opts)
if not route_metadata then
core.log.error("the request uri not match test")
return nil, "the request uri not match test"
end
return opts.matched, nil
end
返回的matched 参数内就包含定义的参数,如我们想取到上面test1 的值可以使用如下方法:
local matched, err = validate_uri()
if not matched then
return
end
print(matched.test1)
这样在我们定义Control API 的时候就可以使用路径参数了