control API 可以被用来:
- 暴露 APISIX 内部状态信息
- 控制单个 APISIX 的数据平面的行为
默认情况下,control API 是启用的,监听 127.0.0.1:9090
。你可以通过修改 apisix/conf/config.yaml
中的 control 部分来更改设置,如下:
apisix:
...
enable_control: true
control:
ip: "127.0.0.1"
port: 9090
复制代码
会在nginx.conf生成一条路由
server {
listen 0.0.0.0:9090;
location / {
content_by_lua_block {
apisix.http_control()
}
}
...
}
复制代码
apisix/init.lua 处理API入口
local control_api_router
local is_http = false
# 在stream子系统下不会引入这个路由
if ngx.config.subsystem == "http" then
is_http = true
control_api_router = require("apisix.control.router")
end
function _M.http_control()
local ok = control_api_router.match(get_var("uri"))
if not ok then
ngx_exit(404)
end
end
复制代码
router.lua 路由匹配
local match_opts = {}
local cached_version
local router
function _M.match(uri)
# 第一次加载是在第一次请求API时赋值
# 这里做了一次缓存,因为插件可以自定义API,所以插件更新也会刷新路由
if cached_version ~= plugin_mod.load_times then
local err
# 注册路由
router, err = fetch_control_api_router()
if router == nil then
core.log.error("failed to fetch valid api router: ", err)
return false
end
cached_version = plugin_mod.load_times
end
core.table.clear(match_opts)
match_opts.method = get_method()
# 执行路由匹配
return router:dispatch(uri, match_opts)
end
复制代码
local routes = {}
local v1_routes = {}
local function empty_func() end
local builtin_v1_routes = require("apisix.control.v1")
function fetch_control_api_router()
...
core.table.clear(v1_routes)
-- 注册默认路由到 v1_routes 上
register_api_routes(v1_routes, builtin_v1_routes)
-- 这里只是注册到v1_routes上
local v1_router, err = router.new(v1_routes)
if not v1_router then
return nil, err
end
-- 这里给默认路由加上/v1/前缀匹配
core.table.insert(routes, {
paths = {"/v1/*"},
filter_fun = function(vars, opts, ...)
local uri = str_sub(vars.uri, #"/v1" + 1)
-- 调用了 v1_routes
return v1_router:dispatch(uri, opts, ...)
end,
handler = empty_func,
})
...
-- 最终注册的路由
return router.new(routes)
end
-- 注册路由匹配到的执行函数
local function register_api_routes(routes, api_routes)
for _, route in ipairs(api_routes) do
core.table.insert(routes, {
methods = route.methods,
paths = route.uris,
handler = function (api_ctx)
-- 执行路由上挂的handler
local code, body = route.handler(api_ctx)
if code or body then
if type(body) == "table" and ngx.header["Content-Type"] == nil then
core.response.set_header("Content-Type", "application/json")
end
-- 直接返回结束
core.response.exit(code, body)
end
end
})
end
end
复制代码
apisix.control.v1 内置路由
-- 具体执行函数
function _M.dump_all_services_info()
-- 从配置中获取的所有服务
local services = get_services()
-- 返回了上面服务的副本
local infos = iter_add_get_services_info(services, nil)
-- 输出
return 200, infos
end
-- 这里返回了所有的内置路由
return {
...
-- /v1/service
{
methods = {"GET"},
uris = {"/service/*"},
handler = _M.dump_all_services_info
}
...
}
复制代码