跳到主要内容

内置变量

APISIX 中的_内置变量_是预定义的变量,可以直接在配置中引用。它们通常用于插件配置、路由匹配和日志自定义。

APISIX 支持三种类型的内置变量:

  • NGINX 变量
  • APISIX 变量
  • 自定义变量

这些变量按 给定的顺序 进行评估。

NGINX 变量

NGINX 提供了一组变量,可用于访问各种特定于请求的信息。

一些常用的变量包括:

  • upstream_addr
  • remote_addr
  • request_uri
  • server_name
  • uri
  • http_user_agent

有关更多信息,请参阅 NGINX 变量的完整列表

APISIX 变量

除了 NGINX 变量 之外,APISIX 还提供了各种内置变量:

变量名描述
post_arg_*当内容类型为 application/x-www-form-urlencoded 时的 HTTP POST 表单数据。星号将替换为 POST 表单数据的实际名称。
post_arg.*当内容类型为 application/jsonapplication/x-www-form-urlencodedmultipart/form-data 时的 HTTP POST 正文参数。星号将替换为 POST 参数的实际名称。支持类似 JSON 路径的选择,例如 post_arg.model.versionpost_arg.messages[*].content[*].type
arg_*URL 查询字符串。星号将替换为实际的查询参数名称。
uri_param_*当 APISIX 使用 radixtree_uri_with_parameter 路由器 时的 URL 参数。星号将替换为实际的查询参数名称。
http_*HTTP 请求头。星号将替换为头的实际名称。
cookie_*请求 Cookie。星号将替换为 Cookie 的实际名称。
balancer_ip上游服务器 IP。
balancer_port上游服务器端口。
consumer_name消费者用户名。
consumer_group_id消费者组 ID。
graphql_nameGraphQL 操作名称
graphql_operationGraphQL 操作类型
graphql_root_fieldsGraphQL 根字段
route_id路由 ID。
route_name路由名称。
service_id服务 ID。
service_name服务名称。
resp_bodyHTTP 响应正文。
mqtt_client_idMQTT 协议中的客户端 ID。
redis_cmd_lineRedis 命令行。
rpc_timeRPC 请求往返时间。

自定义变量

你还可以注册自己的变量并将它们用作内置变量。例如,你可以使用自定义变量来自定义日志插件中的日志格式,或将它们用作限流限速插件中的键。

示例

以下示例演示了注册自定义变量的两种方法,以及如何利用该变量从路由获取信息,随后将该信息记录到远程服务器。

创建服务

创建一个服务以配置 http-logger 插件和上游:

curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"id":"srv_custom_var",
"plugins": {
"http-logger": {
"uri": "'"${REMOTE_SERVER_ADDR}"'"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
}
}
}'

注册自定义变量

你可以选择在源代码中注册自定义变量,或使用 serverless 插件。

方法 1:在源代码中

将以下代码段添加到你的自定义 Lua 文件并引用它,以注册一个名为 a6_route_labels 的自定义变量。该变量表示路由请求中 labels 的值(如果可用):

local core = require "apisix.core"

core.ctx.register_var("a6_route_labels", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels
end
return nil
end)

相应地 启动或重新加载 APISIX。如果 APISIX 已经在运行,请向 /apisix/admin/plugins/reload 发送 PUT 请求以 热加载插件 使更改生效。

警告

虽然从技术上讲,可以将代码段添加到代码引用的任何位置,但在修改 APISIX 核心代码库时要小心,以免对标准功能产生任何负面影响。

建议将你的自定义 Lua 代码保存在单独的目录中,并通过在 config.yaml 配置文件 中配置 extra_lua_pathextra_lua_cpath 来引用它。

有关更多信息,请参阅 创建 Lua 插件指南

方法 2:在 serverless 插件中

你还可以使用 serverless-pre-functionserverless-post-function 无服务器函数插件 注册自定义变量。这些插件在指定的 执行阶段 之前或之后运行无服务器函数,你可以在这些函数中注册自定义变量。

serverless-pre-function 插件添加到之前创建的服务中,其中函数注册自定义变量 a6_route_labels

curl "http://127.0.0.1:9180/apisix/admin/services/srv_custom_var" -X PATCH \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function()
local core = require \"apisix.core\"
core.ctx.register_var(\"a6_route_labels\", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels
end
return nil
end);
end"
]
}
}
}'
方法 3:在插件的 _meta.prefunction

如果你更喜欢在插件中注册自定义变量而不使用 serverless 插件,你可以使用 _meta.pre_function 来配置在插件执行的每个 阶段 之前执行的自定义代码。

以下示例将向你展示如何在 proxy-rewrite 插件中声明 _meta.pre_function,以提取请求路径中的 user_id,将其注册为变量,并使用它来组成新的请求路径。

为了在路由的 URI 中使用参数,你应该首先将 配置文件 中的路由器更新为 radixtree_uri_with_parameter,因为它不是默认设置:

config.yaml
apisix:
router:
http: radixtree_uri_with_parameter

然后 重新加载 APISIX 以使更改生效。

创建一个到 httpbin 服务的路由以检查重写后的路径:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "pre-func-route",
"uri": "/anything/:user_id/hello",
"plugins": {
"proxy-rewrite": {
"_meta": {
"pre_function": "
return function(conf, ctx)
local core = require \"apisix.core\"
core.ctx.register_var(\"user_id\", function(ctx) return ctx.curr_req_matched.user_id end)
end"
},
"uri": "/anything/$user_id/world"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

❶ 匹配请求 /anything/:user_id/hello,其中 user_id 是一个参数。

❷ 自定义 _meta.pre_function 以从请求路径中提取 user_id 值并将其保存到同名变量中。

❸ 将请求路径重写为 /anything/$user_id/world,其中 $user_id 将被替换为变量值。

向路由发送请求:

curl -i "http://127.0.0.1:9080/anything/johndoe/hello"

你应该观察到以下响应,显示请求路径已部分重写为 user_id

{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "text/html..."
...
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 59.71.xxx.xxx",
"url": "http://127.0.0.1/anything/johndoe/world"
}

配置日志格式

创建一个 插件元数据 对象,为所有 http-logger 实例配置日志格式:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/http-logger" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"log_format": {
"host": "$host",
"client_ip": "$remote_addr",
"labels": "$a6_route_labels"
}
}'

hostremote_addr:[NGINX 变量](#NGINX 变量)。

a6_route_labels:自定义变量。

在服务中创建路由

在服务中创建 路由

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"id":"route_custom_var",
"uri":"/get",
"service_id": "srv_custom_var",
"labels": {
"key": "test_a6_route_labels"
}
}'

service_id:对应之前创建的服务。

labels:要与自定义变量一起记录的路由信息。

验证自定义变量注册

发送请求以验证自定义变量是否记录了路由中的 labels 信息:

curl "http://127.0.0.1:9080/get"

你应该在远程服务器中看到一个由 POST 请求创建的日志条目,其正文类似于以下内容:

[
{
"labels": {
"key": "test_a6_route_labels"
},
"service_id": "srv_custom_var",
"client_ip": "172.21.0.1",
"route_id": "route_custom_var",
"host": "127.0.0.1"
}
]

这验证了自定义变量已注册,并且它成功记录了路由中的 labels 信息。

评估顺序

APISIX 按给定顺序评估变量:

  1. 自定义变量
  2. APISIX 变量
  3. NGINX 变量

如果变量在自定义变量中成功获取,APISIX 将不会继续在 APISIX 变量或 NGINX 变量中查找。

换句话说,自定义变量将覆盖 APISIX 变量或 NGINX 变量中定义的同名变量,以更好地满足你的特定用例需求。