【APISIX源码分析】control API

435 阅读1分钟

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
    }
    ...
}