API
网关是微服务架构中的核心基础设施组件,它作为系统的统一入口,承担路由转发、认证授权、限流熔断、协议转换等横切关注点。选择合适的
API 网关对系统的稳定性、性能和可维护性至关重要。本文将深入分析 API
网关的设计原则,并对比两个最流行的开源 API 网关——Kong 和 Apache
APISIX。
sequenceDiagram
participant C as 客户端
participant G as API Gateway
participant US as 用户服务
participant OS as 订单服务
participant PS as 商品服务
C->>G: GET /api/v1/users/123
G->>G: 路由匹配: /api/v1/users/* → user-service
G->>US: GET /users/123
US-->>G: 200 OK
G-->>C: 200 OK
C->>G: POST /api/v1/orders
G->>G: 路由匹配: /api/v1/orders → order-service
G->>OS: POST /orders
OS-->>G: 201 Created
G-->>C: 201 Created
-- 自定义插件: request-transformer-advanced local plugin = { PRIORITY = 1000, VERSION = "1.0.0", }
local schema = { name = "custom-header-injector", fields = { { config = { type = "record", fields = { { request_id_header = { type = "string", default = "X-Request-ID" } }, { add_timestamp = { type = "boolean", default = true } }, }, }}, }, }
functionplugin:access(conf) -- 注入请求 ID local request_id = kong.request.get_header(conf.request_id_header) ifnot request_id then request_id = utils.uuid() kong.service.request.set_header(conf.request_id_header, request_id) end
-- 注入时间戳 if conf.add_timestamp then kong.service.request.set_header("X-Request-Time", ngx.now()) end
-- 记录请求开始时间 kong.ctx.plugin.start_time = ngx.now() end
functionplugin:header_filter(conf) -- 响应中也加入请求 ID local request_id = kong.request.get_header(conf.request_id_header) kong.response.set_header(conf.request_id_header, request_id) end
functionplugin:log(conf) -- 计算请求耗时 local latency = ngx.now() - kong.ctx.plugin.start_time kong.log.info("Request latency: ", latency, "s") end
-- APISIX 自定义插件示例 local core = require("apisix.core") local plugin_name = "custom-auth"
local schema = { type = "object", properties = { header_name = { type = "string", default = "X-API-Key" }, auth_service_url = { type = "string" }, cache_ttl = { type = "integer", default = 300 }, }, required = { "auth_service_url" }, }
local _M = { version = 0.1, priority = 2600, name = plugin_name, schema = schema, }
function_M.check_schema(conf) return core.schema.check(schema, conf) end
function_M.rewrite(conf, ctx) local api_key = core.request.header(ctx, conf.header_name) ifnot api_key then return401, { error = "Missing API key" } end
-- 先检查缓存 local cache_key = "auth:" .. api_key local cached = core.lrucache.global(cache_key, nil, function() -- 调用认证服务验证 local httpc = require("resty.http").new() local res, err = httpc:request_uri(conf.auth_service_url, { method = "POST", body = core.json.encode({ api_key = api_key }), headers = { ["Content-Type"] = "application/json" }, })