feat(apisix): add Cloudron package

- Implements Apache APISIX packaging for Cloudron platform.
- Includes Dockerfile, CloudronManifest.json, and start.sh.
- Configured to use Cloudron's etcd addon.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
This commit is contained in:
2025-09-04 09:42:47 -05:00
parent f7bae09f22
commit 54cc5f7308
1608 changed files with 388342 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
---
title: api-breaker
keywords:
- Apache APISIX
- API 网关
- API Breaker
description: 本文介绍了 Apache APISIX api-breaker 插件的相关操作,你可以使用此插件的 API 熔断机制来保护上游业务服务。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`api-breaker` 插件实现了 API 熔断功能,从而帮助我们保护上游业务服务。
:::note 注意
关于熔断超时逻辑,由代码逻辑自动按**触发不健康状态**的次数递增运算:
当上游服务返回 `unhealthy.http_statuses` 配置中的状态码(默认为 `500`),并达到 `unhealthy.failures` 预设次数时(默认为 3 次),则认为上游服务处于不健康状态。
第一次触发不健康状态时,熔断 2 秒。超过熔断时间后,将重新开始转发请求到上游服务,如果继续返回 `unhealthy.http_statuses` 状态码,记数再次达到 `unhealthy.failures` 预设次数时,熔断 4 秒。依次类推24816……直到达到预设的 `max_breaker_sec`值。
当上游服务处于不健康状态时,如果转发请求到上游服务并返回 `healthy.http_statuses` 配置中的状态码(默认为 `200`),并达到 `healthy.successes` 次时,则认为上游服务恢复至健康状态。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------------- | -------------- | ------ | ---------- | --------------- | -------------------------------- |
| break_response_code | integer | 是 | | [200, ..., 599] | 当上游服务处于不健康状态时返回的 HTTP 错误码。 |
| break_response_body | string | 否 | | | 当上游服务处于不健康状态时返回的 HTTP 响应体信息。 |
| break_response_headers | array[object] | 否 | | [{"key":"header_name","value":"can contain Nginx $var"}] | 当上游服务处于不健康状态时返回的 HTTP 响应头信息。该字段仅在配置了 `break_response_body` 属性时生效,并能够以 `$var` 的格式包含 APISIX 变量,比如 `{"key":"X-Client-Addr","value":"$remote_addr:$remote_port"}`。 |
| max_breaker_sec | integer | 否 | 300 | >=3 | 上游服务熔断的最大持续时间,以秒为单位。 |
| unhealthy.http_statuses | array[integer] | 否 | [500] | [500, ..., 599] | 上游服务处于不健康状态时的 HTTP 状态码。 |
| unhealthy.failures | integer | 否 | 3 | >=1 | 上游服务在一定时间内触发不健康状态的异常请求次数。 |
| healthy.http_statuses | array[integer] | 否 | [200] | [200, ..., 499] | 上游服务处于健康状态时的 HTTP 状态码。 |
| healthy.successes | integer | 否 | 3 | >=1 | 上游服务触发健康状态的连续正常请求次数。 |
## 启用插件
以下示例展示了如何在指定路由上启用 `api-breaker` 插件,该路由配置表示在一定时间内返回 `500``503` 状态码达到 3 次后触发熔断,返回 `200` 状态码 1 次后恢复健康:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/1" \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"api-breaker": {
"break_response_code": 502,
"unhealthy": {
"http_statuses": [500, 503],
"failures": 3
},
"healthy": {
"http_statuses": [200],
"successes": 1
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
按上述配置启用插件后,使用 `curl` 命令请求该路由:
```shell
curl -i -X POST "http://127.0.0.1:9080/hello"
```
如果上游服务在一定时间内返回 `500` 状态码达到 3 次,客户端将会收到 `502 Bad Gateway` 的应答:
```shell
HTTP/1.1 502 Bad Gateway
...
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>openresty</center>
</body>
</html>
```
## 删除插件
当你需要禁用该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,180 @@
---
title: attach-consumer-label
keywords:
- Apache APISIX
- API 网关
- API Consumer
description: 本文介绍了 Apache APISIX attach-consumer-label 插件的相关操作,你可以使用此插件向上游服务传递自定义的 Consumer labels。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`attach-consumer-label` 插件在 X-Consumer-Username 和 X-Credential-Indentifier 之外,还将自定义的消费者相关标签附加到经过身份验证的请求,以便上游服务区分消费者并实现额外的逻辑。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|----------|--------|--------|----------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| headers | object | 是 | | | 要附加到请求标头的 Consumer 标签的键值对,其中键是请求标头名称,例如 "X-Consumer-Role",值是对客户标签键的引用,例如 "$role"。请注意,该值应始终以美元符号 (`$`) 开头。如果 Consumer 上没有配置引用的值,则相应的标头将不会附加到请求中。 |
## 启用插件
下面的示例演示了如何在通过身份验证的请求转发到上游服务之前将自定义标签附加到请求标头。如果请求被拒绝就不会在请求标头上附加任何消费者标签。如果某个标签值未在消费者上配置但在“attach-consumer-label”插件中被引用相应的标头也不会被附加。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
创建一个有自定义标签的 Consumer `john`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john",
# highlight-start
"labels": {
// Annotate 1
"department": "devops",
// Annotate 2
"company": "api7"
}
# highlight-end
}'
```
❶ Consumer 的 `department` 标签信息。
❷ Consumer 的 `company` 标签信息。
为 Consumer `john` 配置 `key-auth`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建路由并启用 `key-auth``attach-consumer-label` 插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "attach-consumer-label-route",
"uri": "/get",
"plugins": {
"key-auth": {},
# highlight-start
"attach-consumer-label": {
"headers": {
// Annotate 1
"X-Consumer-Department": "$department",
// Annotate 2
"X-Consumer-Company": "$company",
// Annotate 3
"X-Consumer-Role": "$role"
}
}
# highlight-end
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
❶ 将 Consumer 标签 `department` 的值附加到请求头的 `X-Consumer-Department` 字段。
❷ 将 Consumer 标签 `company` 的值附加到请求头的 `X-Consumer-Company` 字段。
❸ 将 Consumer 标签 `role` 的值附加到请求头的 `X-Consumer-Role` 字段。由于 Consumer 标签中没有配置 `role` 这个标签,该字段不会出现在发往上游的请求头中。
:::tip
引用标签的值必须以 `$` 符号开头。
:::
使用正确的 apikey 请求该路由,验证插件:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key'
```
可以看到类似的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Apikey": "john-key",
"Host": "127.0.0.1",
# highlight-start
"X-Consumer-Username": "john",
"X-Credential-Indentifier": "cred-john-key-auth",
"X-Consumer-Company": "api7",
"X-Consumer-Department": "devops",
# highlight-end
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/get"
}
```
## 删除插件
当你需要禁用该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/attach-consumer-label-route" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/get",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```

View File

@@ -0,0 +1,272 @@
---
title: authz-casbin
keywords:
- Apache APISIX
- API 网关
- Plugin
- Authz Casbin
- authz-casbin
description: 本文介绍了关于 Apache APISIX `authz-casbin` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`authz-casbin` 插件是一个基于 [Lua Casbin](https://github.com/casbin/lua-casbin/) 的访问控制插件,该插件支持各种 [access control models](https://casbin.org/docs/en/supported-models) 的强大授权场景。
## 属性
| 名称 | 类型 | 必选项 | 描述 |
| ----------- | ------ | ------- | ---------------------------------- |
| model_path | string | 是 | Casbin 鉴权模型配置文件路径。 |
| policy_path | string | 是 | Casbin 鉴权策略配置文件路径。 |
| model | string | 是 | Casbin 鉴权模型的文本定义。 |
| policy | string | 是 | Casbin 鉴权策略的文本定义。 |
| username | string | 是 | 描述请求中有可以通过访问控制的用户名。 |
:::note
你必须在插件配置中指定 `model_path``policy_path``username` 或者指定 `model``policy``username` 才能使插件生效。
如果你想要使所有的 Route 共享 Casbin 配置,你可以先在插件元数据中指定 `model``policy`,在插件配置中仅指定 `username`,这样所有 Route 都可以使用 Casbin 插件配置。
::::
## 元数据
| 名称 | 类型 | 必选项 | 描述 |
| ----------- | ------ | ------- | ------------------------------|
| model | string | 是 | Casbin 鉴权模型的文本定义。 |
| policy | string | 是 | Casbin 鉴权策略的文本定义。 |
## 启用插件
你可以使用 model/policy 文件路径或使用插件 configuration/metadata 中的 model/policy 文本配置在 Route 上启用插件。
### 通过 model/policy 文件路径启用插件
以下示例展示了通过 model/policy 配置文件来设置 Casbin 身份验证:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model_path": "/path/to/model.conf",
"policy_path": "/path/to/policy.csv",
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
### 通过 model/policy 文本配置启用插件
以下示例展示了通过你的 model/policy 文本来设置 Casbin 身份验证:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin",
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
### 通过 plugin metadata 配置模型/策略
首先,我们需要使用 Admin API 发送一个 `PUT` 请求,将 `model``policy` 的配置添加到插件的元数据中。
所有通过这种方式创建的 Route 都会带有一个带插件元数据配置的 Casbin enforcer。你也可以使用这种方式更新 model/policy该插件将会自动同步最新的配置信息。
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/authz-casbin \
-H "X-API-KEY: $admin_key" -i -X PUT -d '
{
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin"
}'
```
更新插件元数据后,可以将插件添加到指定 Route 中:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"authz-casbin": {
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
:::note
插件路由的配置比插件元数据的配置有更高的优先级。因此,如果插件路由的配置中存在 model/policy 配置,插件将优先使用插件路由的配置而不是插件元数据中的配置。
:::
## 测试插件
首先定义测试鉴权模型:
```conf
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)
```
然后添加测试鉴权策略:
```conf
p, *, /, GET
p, admin, *, *
g, alice, admin
```
如果想要了解更多关于 `policy``model` 的配置,请参考 [examples](https://github.com/casbin/lua-casbin/tree/master/examples)
上述配置将允许所有人使用 `GET` 请求访问主页(`/`),而只有具有管理员权限的用户才可以访问其他页面并使用其他请求方法。
简单举例来说,假设我们向主页发出 `GET` 请求,通常都可以返回正常结果。
```shell
curl -i http://127.0.0.1:9080/ -X GET
```
但如果是一个未经授权的普通用户(例如:`bob`)访问除 `/` 以外的其他页面,将得到一个 403 错误:
```shell
curl -i http://127.0.0.1:9080/res -H 'user: bob' -X GET
```
```
HTTP/1.1 403 Forbidden
```
而拥有管理权限的用户(如 `alice`)则可以访问其它页面。
```shell
curl -i http://127.0.0.1:9080/res -H 'user: alice' -X GET
```
## 删除插件
当你需要禁用 `authz-casbin` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/*",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,115 @@
---
title: authz-casdoor
keywords:
- Apache APISIX
- API 网关
- Plugin
- Authz Casdoor
- authz-casdoor
description: 本篇文档介绍了 Apache APISIX auth-casdoor 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
使用 `authz-casdoor` 插件可添加 [Casdoor](https://casdoor.org/) 集中认证方式。
## 属性
| 名称 | 类型 | 必选项 | 描述 |
|---------------|--------|----------|----------------------------------------------|
| endpoint_addr | string | 是 | Casdoor 的 URL。 |
| client_id | string | 是 | Casdoor 的客户端 id。 |
| client_secret | string | 是 | Casdoor 的客户端密钥。 |
| callback_url | string | 是 | 用于接收 code 与 state 的回调地址。 |
注意schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
:::info IMPORTANT
指定 `endpoint_addr``callback_url` 属性时不要以“/”来结尾。
`callback_url` 必须是路由的 URI。具体细节可查看下方示例内容了解相关配置。
:::
## 启用插件
以下示例展示了如何在指定路由上启用 `auth-casdoor` 插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"methods": ["GET"],
"uri": "/anything/*",
"plugins": {
"authz-casdoor": {
"endpoint_addr":"http://localhost:8000",
"callback_url":"http://localhost:9080/anything/callback",
"client_id":"7ceb9b7fda4a9061ec1c",
"client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
## 测试插件
一旦启用了该插件,访问该路由的新用户首先会经过 `authz-casdoor` 插件的处理,然后被重定向到 Casdoor 登录页面。
成功登录后Casdoor 会将该用户重定向到 `callback_url`,并指定 GET 参数的 `code``state`。该插件还会向 Casdoor 请求一个访问 Token并确认用户是否已登录。在成功认证后该流程只出现一次并且后续请求不会被打断。
上述操作完成后,用户就会被重定向到目标 URL。
## 删除插件
当需要禁用 `authz-casdoor` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/anything/*",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```

View File

@@ -0,0 +1,216 @@
---
title: authz-keycloak
keywords:
- Apache APISIX
- API 网关
- Plugin
- Authz Keycloak
- authz-keycloak
description: 本文介绍了关于 Apache APISIX `authz-keycloak` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`authz-keycloak` 插件可用于通过 [Keycloak Identity Server](https://www.keycloak.org/) 添加身份验证。
:::tip
虽然该插件是为了与 Keycloak 一起使用而开发的,但是它也可以与任何符合 OAuth/OIDC 或 UMA 协议的身份认证软件一起使用。
:::
如果你想了解 Keycloak 的更多信息,请参考 [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|----------------------------------------------|---------------|-------|-----------------------------------------------|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| discovery | string | 否 | | https://host.domain/realms/foo/.well-known/uma2-configuration | Keycloak 授权服务的 [discovery document](https://www.keycloak.org/docs/latest/authorization_services/index.html) 的 URL。 |
| token_endpoint | string | 否 | | https://host.domain/realms/foo/protocol/openid-connect/token | 接受 OAuth2 兼容 token 的接口,需要支持 `urn:ietf:params:oauth:grant-type:uma-ticket` 授权类型。 |
| resource_registration_endpoint | string | 否 | | https://host.domain/realms/foo/authz/protection/resource_set | 符合 UMA 的资源注册端点。如果提供,则覆盖发现中的值。 |
| client_id | string | 是 | | | 客户端正在寻求访问的资源服务器的标识符。 |
| client_secret | string | 否 | | | 客户端密码(如果需要)。 |
| grant_type | string | 否 | "urn:ietf:params:oauth:grant-type:uma-ticket" | ["urn:ietf:params:oauth:grant-type:uma-ticket"] | |
| policy_enforcement_mode | string | 否 | "ENFORCING" | ["ENFORCING", "PERMISSIVE"] | |
| permissions | array[string] | 否 | | | 描述客户端应用所需访问的资源和权限范围的字符串。格式必须为:`RESOURCE_ID#SCOPE_ID`。 |
| lazy_load_paths | boolean | 否 | false | [true, false] | 当设置为 true 时,使用资源注册端点而不是静态权限将请求 URI 动态解析为资源。 |
| http_method_as_scope | boolean | 否 | false | [true, false] | 设置为 true 时,将 HTTP 请求类型映射到同名范围并添加到所有请求的权限。 |
| timeout | integer | 否 | 3000 | [1000, ...] | 与 Identity Server 的 HTTP 连接超时(毫秒)。 |
| access_token_expires_in | integer | 否 | 300 | [1, ...] | 访问令牌的有效期。token. |
| access_token_expires_leeway | integer | 否 | 0 | [0, ...] | access_token 更新的到期余地。设置后,令牌将在到期前几秒更新 access_token_expires_leeway。这避免了 access_token 在到达 OAuth 资源服务器时刚刚过期的情况。 |
| refresh_token_expires_in | integer | 否 | 3600 | [1, ...] | 刷新令牌的失效时间。 |
| refresh_token_expires_leeway | integer | 否 | 0 | [0, ...] | refresh_token 更新的到期余地。设置后,令牌将在到期前几秒刷新 refresh_token_expires_leeway。这样可以避免在到达 OAuth 资源服务器时 refresh_token 刚刚过期的错误。 |
| ssl_verify | boolean | 否 | true | [true, false] | 设置为 `true` 时,验证 TLS 证书是否与主机名匹配。 |
| cache_ttl_seconds | integer | 否 | 86400 (equivalent to 24h) | positive integer >= 1 | 插件缓存插件用于向 Keycloak 进行身份验证的发现文档和令牌的最长时间(以秒为单位)。 |
| keepalive | boolean | 否 | true | [true, false] | 当设置为 `true` 时,启用 HTTP keep-alive 保证在使用后仍然保持连接打开。如果您期望对 Keycloak 有很多请求,请设置为 `true`。 |
| keepalive_timeout | integer | 否 | 60000 | positive integer >= 1000 | 已建立的 HTTP 连接将关闭之前的空闲时间。 |
| keepalive_pool | integer | 否 | 5 | positive integer >= 1 | 连接池中的最大连接数。 |
| access_denied_redirect_uri | string | 否 | | [1, 2048] | 需要将用户重定向到的 URI而不是返回类似 `"error_description":"not_authorized"` 这样的错误消息。 |
| password_grant_token_generation_incoming_uri | string | 否 | | /api/token | 将此设置为使用密码授予类型生成令牌。该插件会将传入的请求 URI 与此值进行比较。 |
注意schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
除上述释义外,还有以下需要注意的点:
- Discovery and endpoints
- 使用 `discovery` 属性后,`authz-keycloak` 插件就可以从其 URL 中发现 Keycloak API 的端点。该 URL 指向 Keyloak 针对相应领域授权服务的发现文档。
- 如果发现文档可用,则插件将根据该文档确定令牌端点 URL。如果 URL 存在,则 `token_endpoint``resource_registration_endpoint` 的值将被其覆盖。
- Client ID and secret
- 该插件需配置 `client_id` 属性来标识自身。
- 如果 `lazy_load_paths` 属性被设置为 `true`,那么该插件还需要从 Keycloak 中获得一个自身访问令牌。在这种情况下,如果客户端对 Keycloak 的访问是加密的,就需要配置 `client_secret` 属性。
- Policy enforcement mode
- `policy_enforcement_mode` 属性指定了在处理发送到服务器的授权请求时,该插件如何执行策略。
- `ENFORCING` mode即使没有与给定资源关联的策略请求也会默认被拒绝。`policy_enforcement_mode` 默认设置为 `ENFORCING`
- `PERMISSIVE` mode如果资源没有绑定任何访问策略也被允许请求。
- Permissions
- 在处理传入的请求时,插件可以根据请求的参数确定静态或动态检查 Keycloak 的权限。
- 如果 `lazy_load_paths` 参数设置为 `false`,则权限来自 `permissions` 属性。`permissions` 中的每个条目都需要按照令牌端点预设的 `permission` 属性进行格式化。详细信息请参考 [Obtaining Permissions](https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_obtaining_permissions).
:::note
有效权限可以是单个资源,也可以是与一个或多个范围配对的资源。
:::
如果 `lazy_load_paths` 属性设置为 `true`,则请求 URI 将解析为使用资源注册端点在 Keycloak 中配置的一个或多个资源。已经解析的资源被用作于检查的权限。
:::note
需要该插件从令牌端点为自己获取单独的访问令牌。因此,请确保在 Keycloak 的客户端设置中设置了 `Service Accounts Enabled` 选项。
还需要确保颁发的访问令牌包含具有 `uma_protection` 角色的 `resource_access` 声明,以保证插件能够通过 Protection API 查询资源。
:::
- 自动将 HTTP method 映射到作用域
`http_method_as_scope` 通常与 `lazy_load_paths` 一起使用,但也可以与静态权限列表一起使用。
- 如果 `http_method_as_scope` 属性设置为 `true`,插件会将请求的 HTTP 方法映射到同名范围。然后将范围添加到每个要检查的权限。
- 如果 `lazy_load_paths` 属性设置为 `false`,则插件会将映射范围添加到 `permissions` 属性中配置的任意一个静态权限——即使它们已经包含一个或多个范围。
- 使用 `password` 授权生成令牌
- 如果要使用 `password` 授权生成令牌,你可以设置 `password_grant_token_generation_incoming_uri` 属性的值。
- 如果传入的 URI 与配置的属性匹配并且请求方法是 POST则使用 `token_endpoint` 生成一个令牌。
同时,你还需要添加 `application/x-www-form-urlencoded` 作为 `Content-Type` 标头,`username``password` 作为参数。
如下示例是当 `password_grant_token_generation_incoming_uri` 设置为 `/api/token` 时的命令:
```shell
curl --location --request POST 'http://127.0.0.1:9080/api/token' \
--header 'Accept: application/json, text/plain, */*' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=<User_Name>' \
--data-urlencode 'password=<Password>'
```
## 如何启用
以下示例为你展示了如何在指定 Route 中启用 `authz-keycloak` 插件,其中 `${realm}` 是 Keycloak 中的 `realm` 名称:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/get",
"plugins": {
"authz-keycloak": {
"token_endpoint": "http://127.0.0.1:8090/realms/${realm}/protocol/openid-connect/token",
"permissions": ["resource name#scope name"],
"client_id": "Client ID"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以通过以下方法测试插件。
首先需要从 Keycloak 获取 JWT 令牌:
```shell
curl "http://<YOUR_KEYCLOAK_HOST>/realms/<YOUR_REALM>/protocol/openid-connect/token" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "username=<YOUR_USERNAME>" \
-d "password=<YOUR_PASSWORD>" \
-d "grant_type=password"
```
你应该收到类似以下的响应:
```text
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoT3ludlBPY2d6Y3VWWnYtTU42bXZKMUczb0dOX2d6MFo3WFl6S2FSa1NBIn0.eyJleHAiOjE3MDMyOTAyNjAsImlhdCI6MTcwMzI4OTk2MCwianRpIjoiMjJhOGFmMzItNDM5Mi00Yzg3LThkM2UtZDkyNDVmZmNiYTNmIiwiaXNzIjoiaHR0cDovLzE5Mi4xNjguMS44Mzo4MDgwL3JlYWxtcy9xdWlja3N0YXJ0LXJlYWxtIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjAyZWZlY2VlLTBmYTgtNDg1OS1iYmIwLTgyMGZmZDdjMWRmYSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFwaXNpeC1xdWlja3N0YXJ0LWNsaWVudCIsInNlc3Npb25fc3RhdGUiOiI1YzIzZjVkZC1hN2ZhLTRlMmItOWQxNC02MmI1YzYyNmU1NDYiLCJhY3IiOiIxIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtcXVpY2tzdGFydC1yZWFsbSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiI1YzIzZjVkZC1hN2ZhLTRlMmItOWQxNC02MmI1YzYyNmU1NDYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InF1aWNrc3RhcnQtdXNlciJ9.WNZQiLRleqCxw-JS-MHkqXnX_BPA9i6fyVHqF8l-L-2QxcqTAwbIp7AYKX-z90CG6EdRXOizAEkQytB32eVWXaRkLeTYCI7wIrT8XSVTJle4F88ohuBOjDfRR61yFh5k8FXXdAyRzcR7tIeE2YUFkRqw1gCT_VEsUuXPqm2wTKOmZ8fRBf4T-rP4-ZJwPkHAWc_nG21TmLOBCSulzYqoC6Lc-OvX5AHde9cfRuXx-r2HhSYs4cXtvX-ijA715MY634CQdedheoGca5yzPsJWrAlBbCruN2rdb4u5bDxKU62pJoJpmAsR7d5qYpYVA6AsANDxHLk2-W5F7I_IxqR0YQ","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjN2IwYmY4NC1kYjk0LTQ5YzctYWIyZC01NmU3ZDc1MmRkNDkifQ.eyJleHAiOjE3MDMyOTE3NjAsImlhdCI6MTcwMzI4OTk2MCwianRpIjoiYzcyZjAzMzctYmZhNS00MWEzLTlhYjEtZmJlNGY0NmZjMDgxIiwiaXNzIjoiaHR0cDovLzE5Mi4xNjguMS44Mzo4MDgwL3JlYWxtcy9xdWlja3N0YXJ0LXJlYWxtIiwiYXVkIjoiaHR0cDovLzE5Mi4xNjguMS44Mzo4MDgwL3JlYWxtcy9xdWlja3N0YXJ0LXJlYWxtIiwic3ViIjoiMDJlZmVjZWUtMGZhOC00ODU5LWJiYjAtODIwZmZkN2MxZGZhIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6ImFwaXNpeC1xdWlja3N0YXJ0LWNsaWVudCIsInNlc3Npb25fc3RhdGUiOiI1YzIzZjVkZC1hN2ZhLTRlMmItOWQxNC02MmI1YzYyNmU1NDYiLCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiI1YzIzZjVkZC1hN2ZhLTRlMmItOWQxNC02MmI1YzYyNmU1NDYifQ.7AH7ppbVOlkYc9CoJ7kLSlDUkmFuNga28Amugn2t724","token_type":"Bearer","not-before-policy":0,"session_state":"5c23f5dd-a7fa-4e2b-9d14-62b5c626e546","scope":"email profile"}
```
之后就可以使用获得的访问令牌发起请求:
```shell
curl http://127.0.0.1:9080/get -H 'Authorization: Bearer ${ACCESS_TOKEN}'
```
## 删除插件
当你需要禁用 `authz-keycloak` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/get",
"plugins": {
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
```
## 插件 Roadmap
- 目前,`authz-keycloak` 插件通过要求定义资源名称和所需的范围,来强制执行路由策略。但 Keycloak 官方适配的其他语言客户端Java、JavaScript仍然可以通过动态查询 Keycloak 路径以及延迟加载身份资源的路径来提供路径匹配。在 Apache APISIX 之后发布的插件中即将支持此功能。
- 支持从 Keycloak JSON 文件中读取权限范畴和其他配置项。

View File

@@ -0,0 +1,224 @@
---
title: aws-lambda
keywords:
- Apache APISIX
- Plugin
- AWS Lambda
- aws-lambda
description: 本文介绍了关于 Apache APISIX aws-lambda 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`aws-lambda` 插件用于将 [AWS Lambda](https://aws.amazon.com/lambda/)[Amazon API Gateway](https://aws.amazon.com/api-gateway/) 作为动态上游集成至 APISIX从而实现将访问指定 URI 的请求代理到 AWS 云。
启用 `aws-lambda` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 AWS Lambda Gateway URI 发起一个新的请求。这个新请求中携带了之前配置的授权详细信息,包括请求头、请求体和参数(以上参数都是从原始请求中传递的),然后 `aws-lambda` 插件会将带有响应头、状态码和响应体的响应信息返回给使用 APISIX 发起请求的客户端。
该插件支持通过 AWS API key 和 AWS IAM secrets 进行授权。当使用 AWS IAM secrets 时,该插件支持 [AWS Signature Version 4 signing](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------ - | ------- | -------- | ------- | ------------ | ------------------------------------------------------------ |
| function_uri | string | 是 | | | 触发 lambda serverless 函数的 AWS API Gateway 端点。 |
| authorization | object | 否 | | | 访问云函数的授权凭证。 |
| authorization.apikey | string | 否 | | | 生成的 API 密钥,用于授权对 AWS Gateway 端点的请求。 |
| authorization.iam | object | 否 | | | 用于通过 AWS v4 请求签名执行的基于 AWS IAM 角色的授权。请参考 [IAM 授权方案](#iam-授权方案)。 |
| authorization.iam.accesskey | string | 是 | | 从 AWS IAM 控制台生成的访问密钥 ID。 |
| authorization.iam.secretkey | string | 是 | | 从 AWS IAM 控制台生成的访问密钥。 |
| authorization.iam.aws_region | string | 否 | "us-east-1" | 发出请求的 AWS 区域。有关更多 AWS 区域代码的信息请参考 [AWS 区域代码表](https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#region-names-codes)。 |
| authorization.iam.service | string | 否 | "execute-api" | 接收该请求的服务。若使用 Amazon API gateway APIs, 应设置为 `execute-api`。若使用 Lambda function, 应设置为 `lambda`。 |
| timeout | integer | 否 | 3000 | [100,...] | 代理请求超时(以毫秒为单位)。 |
| ssl_verify | boolean | 否 | true | true/false | 当设置为 `true` 时执行 SSL 验证。 |
| keepalive | boolean | 否 | true | true/false | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 |
| keepalive_pool | integer | 否 | 5 | [1,...] | 在关闭该连接之前,可以在该连接上发送的最大请求数。 |
| keepalive_timeout | integer | 否 | 60000 | [1000,...] | 当连接空闲时,保持该连接处于活动状态的时间,以毫秒为单位。 |
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"aws-lambda": {
"function_uri": "https://x9w6z07gb9.execute-api.us-east-1.amazonaws.com/default/test-apisix",
"authorization": {
"apikey": "<Generated API Key from aws console>"
},
"ssl_verify":false
}
},
"uri": "/aws"
}'
```
通过上述示例配置插件后,任何对 `/aws` URI 的请求(`HTTP/1.1``HTTPS``HTTP2`)都将调用已配置的 AWS 函数的 URI并且会将响应信息返回给客户端。
下述命令的含义是AWS Lambda 从请求中获取 `name` 参数,并返回一条 `"Hello $name"` 消息:
```shell
curl -i -XGET localhost:9080/aws\?name=APISIX
```
正常返回结果:
```shell
HTTP/1.1 200 OK
Content-Type: application/json
...
"Hello, APISIX!"
```
以下示例是客户端通过 HTTP/2 协议与 APISIX 进行通信。
在进行测试之前,由于该 `enable_http2: true` 默认是禁用状态,你可以通过在 `./conf/config.yaml` 中添加 `apisix.node_listen` 下的 `- port: 9081``enable_http2: true` 字段启用。示例如下
```yaml
apisix:
node_listen: # 支持监听多个端口
- 9080
- port: 9081
enable_http2: true # 该字段如果不设置,默认值为 `false`
```
使用 `curl` 命令测试:
```shell
curl -i -XGET --http2 --http2-prior-knowledge localhost:9081/aws\?name=APISIX
```
正常返回结果:
```shell
HTTP/2 200
content-type: application/json
...
"Hello, APISIX!"
```
与上面的示例类似AWS Lambda 函数也可以通过 AWS API Gateway 触发,但需要使用 AWS IAM 权限进行授权。`aws-lambda` 插件的配置文件中包含了 `"authorization"` 字段,用户可以在 HTTP 调用中通过 AWS v4 请求签名。
以下示例展示了如何通过配置文件实现授权:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"aws-lambda": {
"function_uri": "https://ajycz5e0v9.execute-api.us-east-1.amazonaws.com/default/test-apisix",
"authorization": {
"iam": {
"accesskey": "<access key>",
"secretkey": "<access key secret>"
}
},
"ssl_verify": false
}
},
"uri": "/aws"
}'
```
:::note 注意
使用该方法时已经假设你有一个启用了程序化访问的 IAM 用户并具有访问端点的必要权限AmazonAPIGatewayInvokeFullAccess
:::
### 配置路径转发
`aws-lambda` 插件在代理请求到 AWS 上游时也支持 URL 路径转发。基本请求路径的扩展被附加到插件配置中指定的 `function_uri` 字段上。
:::info 重要
因为 APISIX 路由是严格匹配的,所以为了使 `aws-lambda` 插件正常工作,在路由上配置的 `uri` 字段必须以 `*` 结尾,`*` 意味着这个 URI 的任何子路径都会被匹配到同一个路由。
:::
以下示例展示了如何通过配置文件实现路径转发:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"aws-lambda": {
"function_uri": "https://x9w6z07gb9.execute-api.us-east-1.amazonaws.com",
"authorization": {
"apikey": "<Generate API key>"
},
"ssl_verify":false
}
},
"uri": "/aws/*"
}'
```
通过上述示例配置插件后,任何访问 `aws/default/test-apisix` 的请求都会调用 AWS Lambda 函数,并转发附加的参数。
使用 `curl` 命令测试:
```shell
curl -i -XGET http://127.0.0.1:9080/aws/default/test-apisix\?name\=APISIX
```
正常返回结果:
```shell
HTTP/1.1 200 OK
Content-Type: application/json
...
"Hello, APISIX!"
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/aws",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,215 @@
---
title: azure-functions
keywords:
- Apache APISIX
- API 网关
- Plugin
- Azure Functions
- azure-functions
description: 本文介绍了关于 API 网关 Apache APISIX azure-functions 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`azure-functions` 插件用于将 [Azure Serverless Function](https://azure.microsoft.com/en-in/services/functions/) 作为动态上游集成至 APISIX从而实现将访问指定 URI 的请求代理到 Microsoft Azure 云服务。
启用 `azure-functions` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 Azure Functions 发起一个新的请求。该新请求中携带了之前配置的授权详细信息,包括请求头、请求体和参数(以上参数都是从原始请求中传递的)。之后便会通过 `azure-functions` 插件,将带有响应头、状态码和响应体的信息返回给使用 APISIX 发起请求的客户端。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | ------- | ------ | ------ | ---------- | ------------------------------------------------------------ |
| function_uri | string | 是 | | | 触发 Serverless Functions 的 Azure Functions 端点。例如 `http://test-apisix.azurewebsites.net/api/HttpTrigger`。 |
| authorization | object | 否 | | | 访问 Azure Functions 的授权凭证。 |
| authorization.apikey | string | 否 | | | 授权凭证内的字段。生成 API 密钥来授权对端点的请求。 |
| authorization.clientid | string | 否 | | | 授权凭证内的字段。生成客户端 IDAzure Active Directory来授权对端点的请求。 |
| timeout | integer | 否 | 3000 | [100,...] | 代理请求超时(以毫秒为单位)。 |
| ssl_verify | boolean | 否 | true | true/false | 当设置为 `true` 时执行 SSL 验证。 |
| keepalive | boolean | 否 | true | true/false | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 |
| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 |
| keepalive_timeout | integer | 否 | 60000 | [1000,...] | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 |
## 元数据
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| --------------- | ------ | ------ | ------ | ------------------------------------------------------------ |
| master_apikey | string | 否 | "" | 可用于访问 Azure Functions URI 的 API 密钥。 |
| master_clientid | string | 否 | "" | 可用于授权 Azure Functions URI 的客户端 IDActive Directory。 |
`azure-functions` 插件的元数据提供了授权回退的功能。它定义了 `master_apikey``master_clientid` 字段,用户可以为关键任务的应用部署声明 API 密钥或客户端 ID。因此如果在 `azure-functions` 插件属性中没有找到相关授权凭证,此时元数据中的授权凭证就会发挥作用。
:::note 注意
授权方式优先级排序如下:
1. 首先,`azure-functions` 插件在 APISIX 代理的请求头中寻找 `x-functions-key``x-functions-clientid` 键。
2. 如果没有找到,`azure-functions` 插件会检查插件属性中的授权凭证。如果授权凭证存在,`azure-functions` 插件会将相应的授权标头添加到发送到 Azure Functions 的请求中。
3. 如果未配置 `azure-functions` 插件的授权凭证属性APISIX 将获取插件元数据配置并使用 API 密钥。
:::
如果你想添加一个新的 API 密钥,请向 `/apisix/admin/plugin_metadata` 端点发出请求,并附上所需的元数据。示例如下:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/azure-functions \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"master_apikey" : "<Your Azure master access key>"
}'
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件,请确保你的 Azure Functions 已提前部署好,并正常提供服务。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"azure-functions": {
"function_uri": "http://test-apisix.azurewebsites.net/api/HttpTrigger",
"authorization": {
"apikey": "${Generated API key to access the Azure-Function}"
}
}
},
"uri": "/azure"
}'
```
通过上述示例配置插件后,任何对 `/azure` URI 的请求(`HTTP/1.1``HTTPS``HTTP2`)都将调用已配置的 Azure Functions 的 URI并且会将响应信息返回给客户端。
下述命令的含义是Azure Functions 从请求中获取 `name` 参数,并返回一条 `"Hello $name"` 消息:
```shell
curl -i -XGET http://localhost:9080/azure\?name=APISIX
```
正常返回结果:
```shell
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
...
Hello, APISIX
```
以下示例是客户端通过 HTTP/2 协议与 APISIX 进行通信。
在进行测试之前,由于该 `enable_http2: true` 默认是禁用状态,你可以通过在 `./conf/config.yaml` 中添加 `apisix.node_listen` 下的 `- port: 9081``enable_http2: true` 字段启用。示例如下:
```yaml
apisix:
node_listen: # 支持监听多个端口
- 9080
- port: 9081
enable_http2: true # 该字段如果不设置,默认值为 `false`
```
使用 `curl` 命令测试:
```shell
curl -i -XGET --http2 --http2-prior-knowledge http://localhost:9081/azure\?name=APISIX
```
正常返回结果:
```shell
HTTP/2 200
content-type: text/plain; charset=utf-8
...
Hello, APISIX
```
### 配置路径转发
`azure-functions` 插件在代理请求到 Azure Functions 上游时也支持 URL 路径转发。基本请求路径的扩展被附加到插件配置中指定的 `function_uri` 字段上。
:::info 重要
因为 APISIX 路由是严格匹配的,所以为了使 `azure-functions` 插件正常工作,在路由上配置的 `uri` 字段必须以 `*` 结尾,`*` 意味着这个 URI 的任何子路径都会被匹配到同一个路由。
:::
以下示例展示了如何通过配置文件实现路径转发:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"azure-functions": {
"function_uri": "http://app-bisakh.azurewebsites.net/api",
"authorization": {
"apikey": "${Generated API key to access the Azure-Function}"
}
}
},
"uri": "/azure/*"
}'
```
通过上述示例配置插件后,任何访问 `azure/HttpTrigger1` 的请求都会调用 Azure Functions 并转发附加的参数。
使用 `curl` 命令测试:
```shell
curl -i -XGET http://127.0.0.1:9080/azure/HttpTrigger1\?name\=APISIX\
```
正常返回结果:
```shell
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
...
Hello, APISIX
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/azure",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,512 @@
---
title: basic-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- Basic Auth
- basic-auth
description: basic-auth 插件为消费者添加了基本访问身份验证,以便消费者在访问上游资源之前进行身份验证。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/basic-auth" />
</head>
## 描述
`basic-auth` 插件为 [消费者](../terminology/consumer.md) 添加了 [基本访问身份验证](https://en.wikipedia.org/wiki/Basic_access_authentication),以便消费者在访问上游资源之前进行身份验证。
当消费者成功通过身份验证后APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username``X-Credential-Indentifier` 和其他消费者自定义标头(如果已配置)。上游服务将能够区分消费者并根据需要实现其他逻辑。如果这些值中的任何一个不可用,则不会添加相应的标头。
## 属性
Consumer/Credentials 端:
| 名称 | 类型 | 必选项 | 描述 |
| -------- | ------ | -----| ----------------------------------------------------------------------------------------------- |
| username | string | 是 | Consumer 的用户名并且该用户名是唯一,如果多个 Consumer 使用了相同的 `username`,将会出现请求匹配异常。|
| password | string | 是 | 用户的密码。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
注意schema 中还定义了 `encrypt_fields = {"password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
Route 端:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ---------------- | ------- | ------ | ------ | --------------------------------------------------------------- |
| hide_credentials | boolean | 否 | false | 该参数设置为 `true` 时,则不会将 Authorization 请求头传递给 Upstream。|
| anonymous_consumer | boolean | 否 | false | 匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。 |
## 示例
以下示例演示了如何在不同场景中使用 `basic-auth` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
### 在路由上实现基本身份验证
以下示例演示如何在路由上实现基本身份验证。
创建消费者 `johndoe`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "johndoe"
}'
```
为消费者创建 `basic-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
```
创建一个带有 `basic-auth` 的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
#### 使用有效密钥进行验证
使用有效密钥发送请求至:
```shell
curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"headers": {
"Accept": "*/*",
"Apikey": "john-key",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc",
"X-Consumer-Username": "john",
"X-Credential-Indentifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/get"
}
```
#### 使用无效密钥进行验证
使用无效密钥发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-key
```
您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"Invalid user authorization"}
```
#### 无需密钥即可验证
无需密钥即可发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"Missing authorization in request"}
```
### 隐藏上游的身份验证信息
以下示例演示了如何通过配置 `hide_credentials` 来防止密钥被发送到上游服务。APISIX 默认情况下会将身份验证密钥转发到上游服务,这在某些情况下可能会导致安全风险,您应该考虑更新 `hide_credentials`
创建消费者 `johndoe`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "johndoe"
}'
```
为消费者创建 `basic-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
```
#### 不隐藏凭据
使用 `basic-auth` 创建路由,并将 `hide_credentials` 配置为 `false`,这是默认配置:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-auth": {
"hide_credentials": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送带有有效密钥的请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key
```
您应该看到以下 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66cc2195-22bd5f401b13480e63c498c6",
"X-Consumer-Username": "john",
"X-Credential-Indentifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 43.228.226.23",
"url": "http://127.0.0.1/anything"
}
```
请注意,凭证以 base64 编码格式对上游服务可见。
:::tip
您还可以使用 `Authorization` 标头在请求中传递 base64 编码的凭据,如下所示:
```shell
curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ=="
```
:::
#### 隐藏凭据
将插件的 `hide_credentials` 更新为 `true`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"basic-auth": {
"hide_credentials": true
}
}
}'
```
发送带有有效密钥的请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key
```
您应该看到以下 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66cc21a7-4f6ac87946e25f325167d53a",
"X-Consumer-Username": "john",
"X-Credential-Indentifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 43.228.226.23",
"url": "http://127.0.0.1/anything"
}
```
请注意,上游服务不再可见这些凭据。
### 将消费者自定义 ID 添加到标头
以下示例演示了如何在 `Consumer-Custom-Id` 标头中将消费者自定义 ID 附加到经过身份验证的请求,该 ID 可用于根据需要实现其他逻辑。
创建带有自定义 ID 标签的消费者 `johndoe`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "johndoe",
"labels": {
"custom_id": "495aec6a"
}
}'
```
为消费者创建 `basic-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
```
创建一个带有 `basic-auth` 的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用有效密钥向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key
```
您应该看到一个带有 `X-Consumer-Custom-Id``HTTP/1.1 200 OK` 响应,类似于以下内容:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea8d64-33df89052ae198a706e18c2a",
"X-Consumer-Username": "johndoe",
"X-Credential-Identifier": "cred-john-basic-auth",
"X-Consumer-Custom-Id": "495aec6a",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/anything"
}
```
### 匿名消费者的速率限制
以下示例演示了如何为普通消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证,并且配额较少。
创建普通消费者 `johndoe` 并配置 `limit-count` 插件以允许 30 秒内的配额为 3
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "johndoe",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
为消费者 `johndoe` 创建 `basic-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
```
创建匿名用户 `anonymous`,并配置 `limit-count` 插件,以允许 30 秒内配额为 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
创建一个路由并配置 `basic-auth` 插件来接受匿名消费者 `anonymous` 绕过身份验证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
为了验证,请使用 `john` 的密钥发送五个连续的请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john-key -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 5 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200: 3, 429: 2
```
发送五个匿名请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,表明只有一个请求成功:
```text
200: 1, 429: 4
```

View File

@@ -0,0 +1,234 @@
---
title: batch-requests
keywords:
- Apache APISIX
- API 网关
- Plugin
- Batch Requests
description: 本文介绍了关于 Apache APISIX `batch-request` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
在启用 `batch-requests` 插件后,用户可以通过将多个请求组装成一个请求的形式,把请求发送给网关,网关会从请求体中解析出对应的请求,再分别封装成独立的请求,以 [HTTP pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式代替用户向网关自身再发起多个 HTTP 请求,经历路由匹配,转发到对应上游等多个阶段,合并结果后再返回客户端。
![batch-request](https://static.apiseven.com/uploads/2023/06/27/ATzEuOn4_batch-request.png)
在客户端需要访问多个 API 的情况下,这将显著提高性能。
:::note
用户原始请求中的请求头(除了以 `Content-` 开始的请求头,例如:`Content-Type`)将被赋给 HTTP pipeline 中的每个请求,因此对于网关来说,这些以 HTTP pipeline 方式发送给自身的请求与用户直接发起的外部请求没有什么不同,只能访问已经配置好的路由,并将经历完整的鉴权过程,因此不存在安全问题。
如果原始请求的请求头与插件中配置的请求头冲突,则以插件中配置的请求头优先(配置文件中指定的 real_ip_header 除外)。
:::
## 属性
无。
## 接口
该插件会增加 `/apisix/batch-requests` 接口。
:::note
你需要通过 [public-api](../../../zh/latest/plugins/public-api.md) 插件来暴露它。
:::
## 启用插件
该插件默认是禁用状态,你可以在配置文件(`./conf/config.yaml`)添加如下配置启用 `batch-requests` 插件:
```yaml title="conf/config.yaml"
plugins:
- ...
- batch-requests
```
## 配置插件
默认情况下,可以发送到 `/apisix/batch-requests` 的最大请求体不能大于 1 MiB。你可以通过 `apisix/admin/plugin_metadata/batch-requests` 更改插件的此配置:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/batch-requests \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"max_body_size": 4194304
}'
```
## 元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------- | ------- | -------| ------- | ------ | ---------------------------- |
| max_body_size | integer | 是 | 1048576 |[1, ...]| 请求体的最大大小单位bytes。 |
## 请求和响应格式
该插件会为 `apisix` 创建一个 `/apisix/batch-requests` 的接口,用来处理批量请求。
### 请求参数
| 参数名 | 类型 | 必选项 | 默认值 | 描述 |
| -------- |------------------------------------| ------ | ------ | -------------------------------- |
| query | object | 否 | | 给所有请求都携带的 `query string`。 |
| headers | object | 否 | | 给所有请求都携带的 `header`。 |
| timeout | number | 否 | 30000 | 聚合请求的超时时间,单位为 `ms`。 |
| pipeline | array[[HttpRequest](#httprequest)] | 是 | | HTTP 请求的详细信息。 |
#### HttpRequest
| 参数名 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------- | ------- | -------- | ------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| version | string | 否 | 1.1 | [1.0, 1.1] | 请求所使用的 HTTP 协议版本。 |
| method | string | 否 | GET | ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE"] | 请求使用的 HTTP 方法。 |
| query | object | 否 | | | 独立请求所携带的 `query string`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
| headers | object | 否 | | | 独立请求所携带的 `header`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
| path | string | 是 | | | HTTP 请求路径。 |
| body | string | 否 | | | HTTP 请求体。 |
| ssl_verify | boolean | 否 | false | | 验证 SSL 证书与主机名是否匹配。 |
### 响应参数
返回值是一个 [HttpResponse](#httpresponse) 的`数组`。
#### HttpResponse
| 参数名 | 类型 | 描述 |
| ------- | ------- | ------------------- |
| status | integer | HTTP 请求的状态码。 |
| reason | string | HTTP 请求的返回信息。 |
| body | string | HTTP 请求的响应体。 |
| headers | object | HTTP 请求的响应头。 |
## 修改自定义 URI
你可以通过 [public-api](../../../en/latest/plugins/public-api.md) 插件设置自定义 URI。
只需要在创建路由时设置所需的 URI 并更改 `public-api` 插件的配置:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/br \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/batch-requests",
"plugins": {
"public-api": {
"uri": "/apisix/batch-requests"
}
}
}'
```
## 测试插件
首先,你需要为 `batch-requests` 插件的 API 创建一个路由,它将使用 [public-api](../../../en/latest/plugins/public-api.md) 插件。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/apisix/batch-requests",
"plugins": {
"public-api": {}
}
}'
```
之后,你就可以将要访问的请求信息传到网关的批量请求接口(`/apisix/batch-requests`)了,网关会以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式自动帮你完成请求。
```shell
curl --location --request POST 'http://127.0.0.1:9080/apisix/batch-requests' \
--header 'Content-Type: application/json' \
--data '{
"headers": {
"Content-Type": "application/json",
"admin-jwt":"xxxx"
},
"timeout": 500,
"pipeline": [
{
"method": "POST",
"path": "/community.GiftSrv/GetGifts",
"body": "test"
},
{
"method": "POST",
"path": "/community.GiftSrv/GetGifts",
"body": "test2"
}
]
}'
```
正常返回结果如下:
```json
[
{
"status": 200,
"reason": "OK",
"body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}",
"headers": {
"Connection": "keep-alive",
"Date": "Sat, 11 Apr 2020 17:53:20 GMT",
"Content-Type": "application/json",
"Content-Length": "81",
"Server": "APISIX web server"
}
},
{
"status": 200,
"reason": "OK",
"body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}",
"headers": {
"Connection": "keep-alive",
"Date": "Sat, 11 Apr 2020 17:53:20 GMT",
"Content-Type": "application/json",
"Content-Length": "81",
"Server": "APISIX web server"
}
}
]
```
## 删除插件
如果你想禁用插件,可以将 `batch-requests` 从配置文件中的插件列表删除,重新加载 APISIX 后即可生效。
```yaml title="conf/config.yaml"
plugins: # plugin list
- ...
```

View File

@@ -0,0 +1,609 @@
---
title: body-transformer
keywords:
- Apache APISIX
- API 网关
- Plugin
- BODY TRANSFORMER
- body-transformer
description: body-transformer 插件执行基于模板的转换,将请求和/或响应主体从一种格式转换为另一种格式,例如从 JSON 到 JSON、从 JSON 到 HTML 或从 XML 到 YAML。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/body-transformer" />
</head>
## 描述
`body-transformer` 插件执行基于模板的转换,将请求和/或响应主体从一种格式转换为另一种格式,例如从 JSON 到 JSON、从 JSON 到 HTML 或从 XML 到 YAML。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|--------------|----------------------|-------|---------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| `request` | object | 否 | | | 请求体转换配置。 |
| `request.input_format` | string | 否 | | [`xml`,`json`,`encoded`,`args`,`plain`,`multipart`] | 请求体原始媒体类型。若未指定,则该值将由 `Content-Type` 标头确定以应用相应的解码器。`xml` 选项对应于 `text/xml` 媒体类型。`json` 选项对应于 `application/json` 媒体类型。`encoded` 选项对应于 `application/x-www-form-urlencoded` 媒体类型。`args` 选项对应于 GET 请求。`plain` 选项对应于 `text/plain` 媒体类型。`multipart` 选项对应于 `multipart/related` 媒体类型。如果媒体类型不是这两种类型,则该值将保留未设置状态并直接应用转换模板。 |
| `request.template` | string | True | | | 请求体转换模板。模板使用 [lua-resty-template](https://github.com/bungle/lua-resty-template) 语法。有关更多详细信息,请参阅 [模板语法](https://github.com/bungle/lua-resty-template#template-syntax)。您还可以使用辅助函数 `_escape_json()``_escape_xml()` 转义双引号等特殊字符,使用 `_body` 访问请求正文,使用 `_ctx` 访问上下文变量。|
| `request.template_is_base64` | boolean | 否 | false | | 如果模板是 base64 编码的,则设置为 true。|
| `response` | object | 否 | | | 响应体转换配置。|
| `response.input_format` | string | 否 | | [`xml`,`json`] | 响应体原始媒体类型。如果未指定,则该值将由 `Content-Type` 标头确定以应用相应的解码器。如果媒体类型既不是 `xml` 也不是 `json`,则该值将保留未设置状态,并直接应用转换模板。|
| `response.template` | string | True | | | 响应主体转换模板。|
| `response.template_is_base64` | boolean | 否 | false | | 如果模板是 base64 编码的,则设置为 true。|
## 示例
以下示例演示了如何针对不同场景配置 `body-transformer`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
转换模板使用 [lua-resty-template](https://github.com/bungle/lua-resty-template) 语法。请参阅 [模板语法](https://github.com/bungle/lua-resty-template#template-syntax) 了解更多信息。
您还可以使用辅助函数 `_escape_json()``_escape_xml()` 转义特殊字符(例如双引号)、`_body` 访问请求正文以及 `_ctx` 访问上下文变量。
在所有情况下,您都应确保转换模板是有效的 JSON 字符串。
### JSON 和 XML SOAP 之间的转换
以下示例演示了在使用 SOAP 上游服务时如何将请求主体从 JSON 转换为 XML将响应主体从 XML 转换为 JSON。
启动示例 SOAP 服务:
```shell
cd /tmp
git clone https://github.com/spring-guides/gs-soap-service.git
cd gs-soap-service/complete
./mvnw spring-boot:run
```
创建请求和响应转换模板:
```shell
req_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
<?xml version="1.0"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:getCountryRequest xmlns:ns0="http://spring.io/guides/gs-producing-web-service">
<ns0:name>{{_escape_xml(name)}}</ns0:name>
</ns0:getCountryRequest>
</soap-env:Body>
</soap-env:Envelope>
EOF
)
rsp_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
{% if Envelope.Body.Fault == nil then %}
{
"status":"{{_ctx.var.status}}",
"currency":"{{Envelope.Body.getCountryResponse.country.currency}}",
"population":{{Envelope.Body.getCountryResponse.country.population}},
"capital":"{{Envelope.Body.getCountryResponse.country.capital}}",
"name":"{{Envelope.Body.getCountryResponse.country.name}}"
}
{% else %}
{
"message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*},
"code":"{{Envelope.Body.Fault.faultcode}}"
{% if Envelope.Body.Fault.faultactor ~= nil then %}
, "actor":"{{Envelope.Body.Fault.faultactor}}"
{% end %}
}
{% end %}
EOF
)
```
上面使用了 `awk``tr` 来操作模板,使模板成为有效的 JSON 字符串。
使用之前创建的模板创建带有 `body-transformer` 的路由。在插件中,将请求输入格式设置为 JSON将响应输入格式设置为 XML并将 `Content-Type` 标头设置为 `text/xml`,以便上游服务正确响应:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"methods": ["POST"],
"uri": "/ws",
"plugins": {
"body-transformer": {
"request": {
"template": "'"$req_template"'",
"input_format": "json"
},
"response": {
"template": "'"$rsp_template"'",
"input_format": "xml"
}
},
"proxy-rewrite": {
"headers": {
"set": {
"Content-Type": "text/xml"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"localhost:8080": 1
}
}
}'
```
:::tip
如果将复杂的文本文件调整为有效的转换模板很麻烦,则可以使用 base64 实用程序对文件进行编码,例如以下内容:
```json
"body-transformer": {
"request": {
"template": "'"$(base64 -w0 /path/to/request_template_file)"'"
},
"response": {
"template": "'"$(base64 -w0 /path/to/response_template_file)"'"
}
}
```
:::
发送具有有效 JSON 主体的请求:
```shell
curl "http://127.0.0.1:9080/ws" -X POST -d '{"name": "Spain"}'
```
请求中发送的 JSON 主体将在转发到上游 SOAP 服务之前转换为 XML响应主体将从 XML 转换回 JSON。
您应该会看到类似以下内容的响应:
```json
{
"status": "200",
"currency": "EUR",
"population": 46704314,
"capital": "Madrid",
"name": "Spain"
}
```
### 修改请求体
以下示例演示了如何动态修改请求体。
使用 `body-transformer` 创建一个路由,其中​​模板将单词 `world` 附加到 `name`,并将 `10` 添加到 `age`,以将它们分别设置为 `foo``bar` 的值:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"template": "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路线发送请求:
```shell
curl "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{"name":"hello","age":20}' \
-i
```
您应该看到以下响应:
```json
{
"args": {},
"data": "{\"foo\":\"hello world\",\"bar\":30}",
...
"json": {
"bar": 30,
"foo": "hello world"
},
"method": "POST",
...
}
```
### 使用变量生成请求主体
以下示例演示如何使用 `ctx` 上下文变量动态生成请求主体。
使用 `body-transformer` 创建路由,其中​​模板使用 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html) `arg_name` 访问请求参数:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"template": "{\"foo\":\"{{_ctx.var.arg_name .. \" world\"}}\"}"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用 `name` 参数向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?name=hello"
```
您应该看到如下响应:
```json
{
"args": {
"name": "hello"
},
...,
"json": {
"foo": "hello world"
},
...
}
```
### 将正文从 YAML 转换为 JSON
以下示例演示如何将请求正文从 YAML 转换为 JSON。
创建请求转换模板:
```shell
req_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1'
{%
local yaml = require("tinyyaml")
local body = yaml.parse(_body)
%}
{"foobar":"{{body.foobar.foo .. " " .. body.foobar.bar}}"}
EOF
)
```
使用以下模板创建一个带有 `body-transformer` 的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"template": "'"$req_template"'"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用 YAML 主体向路由发送请求:
```shell
body='
foobar:
foo: hello
bar: world'
curl "http://127.0.0.1:9080/anything" -X POST \
-d "$body" \
-H "Content-Type: text/yaml" \
-i
```
您应该会看到类似以下内容的响应,这验证了 YAML 主体已适当地转换为 JSON
```json
{
"args": {},
"data": "{\"foobar\":\"hello world\"}",
...
"json": {
"foobar": "hello world"
},
...
}
```
### 将表单 URL 编码主体转换为 JSON
以下示例演示如何将 `form-urlencoded` 主体转换为 JSON。
使用 `body-transformer` 创建路由,将 `input_format` 设置为 `encoded`,并配置一个模板,将字符串 `world` 附加到 `name` 输入,将 `10` 添加到 `age` 输入:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"input_format": "encoded",
"template": "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送一个带有编码主体的 POST 请求:
```shell
curl "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'name=hello&age=20'
```
您应该会看到类似以下内容的响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"foo\":\"hello world\",\"bar\":30}": ""
},
"headers": {
...
},
...
}
```
### 将 GET 请求查询参数转换为正文
以下示例演示如何将 GET 请求查询参数转换为请求正文。请注意,这不会转换 HTTP 方法。要转换方法,请参阅 [`proxy-rewrite`](./proxy-rewrite.md)
使用 `body-transformer` 创建路由,将 `input_format` 设置为 `args`,并配置一个向请求添加消息的模板:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"input_format": "args",
"template": "{\"message\": \"hello {{name}}\"}"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路线发送 GET 请求:
```shell
curl "http://127.0.0.1:9080/anything?name=john"
```
您应该会看到类似以下内容的响应:
```json
{
"args": {},
"data": "{\"message\": \"hello john\"}",
"files": {},
"form": {},
"headers": {
...
},
"json": {
"message": "hello john"
},
"method": "GET",
...
}
```
### 转换纯文本媒体类型
以下示例演示如何转换具有 `plain` 媒体类型的请求。
使用 `body-transformer` 创建路由,将 `input_format` 设置为 `plain`,并配置模板以从正文字符串中删除 `not` 和后续空格:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"input_format": "plain",
"template": "{\"message\": \"{* string.gsub(_body, \"not \", \"\") *}\"}"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送 POST 请求:
```shell
curl "http://127.0.0.1:9080/anything" -X POST \
-d 'not actually json' \
-i
```
您应该会看到类似以下内容的响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"message\": \"actually json\"}": ""
},
"headers": {
...
},
...
}
```
### 转换多部分媒体类型
以下示例演示如何转换具有 `multipart` 媒体类型的请求。
创建一个请求转换模板,该模板根据请求正文中提供的 `age` 向正文添加 `status`
```shell
req_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1'
{%
local core = require 'apisix.core'
local cjson = require 'cjson'
if tonumber(context.age) > 18 then
context._multipart:set_simple("status", "adult")
else
context._multipart:set_simple("status", "minor")
end
local body = context._multipart:tostring()
%}{* body *}
EOF
)
```
创建一个带有 `body-transformer` 的路由,将 `input_format` 设置为 `multipart`,并使用之前创建的请求模板进行转换:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "body-transformer-route",
"uri": "/anything",
"plugins": {
"body-transformer": {
"request": {
"input_format": "multipart",
"template": "'"$req_template"'"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送多部分 POST 请求:
```shell
curl -X POST \
-F "name=john" \
-F "age=10" \
"http://127.0.0.1:9080/anything"
```
您应该会看到类似以下内容的响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"age": "10",
"name": "john",
"status": "minor"
},
"headers": {
"Accept": "*/*",
"Content-Length": "361",
"Content-Type": "multipart/form-data; boundary=------------------------qtPjk4c8ZjmGOXNKzhqnOP",
...
},
...
}
```

View File

@@ -0,0 +1,133 @@
---
title: brotli
keywords:
- Apache APISIX
- API 网关
- Plugin
- brotli
description: 这个文档包含有关 Apache APISIX brotli 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`brotli` 插件可以动态的设置 Nginx 中的 [brotli](https://github.com/google/ngx_brotli) 的行为。
## 前提条件
该插件依赖 brotli 共享库。
如下是构建和安装 brotli 共享库的示例脚本:
``` shell
wget https://github.com/google/brotli/archive/refs/tags/v1.1.0.zip
unzip v1.1.0.zip
cd brotli-1.1.0 && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/brotli ..
sudo cmake --build . --config Release --target install
sudo sh -c "echo /usr/local/brotli/lib >> /etc/ld.so.conf.d/brotli.conf"
sudo ldconfig
```
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|--------------|----------------------|-------|---------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| types | array[string] or "*" | False | ["text/html"] | | 动态设置 `brotli_types` 指令。特殊值 `"*"` 用于匹配任意的 MIME 类型。 |
| min_length | integer | False | 20 | >= 1 | 动态设置 `brotli_min_length` 指令。 |
| comp_level | integer | False | 6 | [0, 11] | 动态设置 `brotli_comp_level` 指令。 |
| mode | integer | False | 0 | [0, 2] | 动态设置 `brotli decompress mode`,更多信息参考 [RFC 7932](https://tools.ietf.org/html/rfc7932)。 |
| lgwin | integer | False | 19 | [0, 10-24] | 动态设置 `brotli sliding window size``lgwin` 是滑动窗口大小的以 2 为底的对数,将其设置为 0 会让压缩器自行决定最佳值,更多信息请参考 [RFC 7932](https://tools.ietf.org/html/rfc7932)。 |
| lgblock | integer | False | 0 | [0, 16-24] | 动态设置 `brotli input block size``lgblock` 是最大输入块大小的以 2 为底的对数,将其设置为 0 会让压缩器自行决定最佳值,更多信息请参考 [RFC 7932](https://tools.ietf.org/html/rfc7932)。 |
| http_version | number | False | 1.1 | 1.1, 1.0 | 与 `gzip_http_version` 指令类似,用于识别 http 的协议版本。 |
| vary | boolean | False | false | | 与 `gzip_vary` 指令类似,用于启用或禁用 `Vary: Accept-Encoding` 响应头。 |
## 启用插件
如下示例中,在指定的路由上启用 `brotli` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/",
"plugins": {
"brotli": {
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
## 使用示例
通过上述命令启用插件后,可以通过以下方法测试插件:
```shell
curl http://127.0.0.1:9080/ -i -H "Accept-Encoding: br"
```
```
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Tue, 05 Dec 2023 03:06:49 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.6.0
Content-Encoding: br
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
```
## 删除插件
当您需要禁用 `brotli` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```

View File

@@ -0,0 +1,263 @@
---
title: chaitin-waf
keywords:
- Apache APISIX
- API 网关
- Plugin
- WAF
description: 本文介绍了关于 Apache APISIX `chaitin-waf` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
在启用 `chaitin-waf` 插件后,流量将被转发给长亭 WAF 服务,用以检测和防止各种 Web 应用程序攻击,以保护应用程序和用户数据的安全。
## 响应头
根据插件配置,可以选择是否附加额外的响应头。
响应头的信息如下:
- **X-APISIX-CHAITIN-WAF**APISIX 是否将请求转发给 WAF 服务器。
- yes转发
- no不转发
- unhealthy符合匹配条件但没有可用的 WAF 服务器
- err插件执行过程中出错。此时会附带 **X-APISIX-CHAITIN-WAF-ERROR** 请求头
- waf-err与 WAF 服务器交互时出错。此时会附带 **X-APISIX-CHAITIN-WAF-ERROR** 请求头
- timeout与 WAF 服务器的交互超时
- **X-APISIX-CHAITIN-WAF-ERROR**调试用响应头。APISIX 与 WAF 交互时的错误信息。
- **X-APISIX-CHAITIN-WAF-TIME**APISIX 与 WAF 交互所耗费的时间,单位是毫秒。
- **X-APISIX-CHAITIN-WAF-STATUS**WAF 服务器返回给 APISIX 的状态码。
- **X-APISIX-CHAITIN-WAF-ACTION**WAF 服务器返回给 APISIX 的处理结果。
- pass请求合法
- reject请求被 WAF 服务器拒绝
- **X-APISIX-CHAITIN-WAF-SERVER**:调试用响应头。所使用的 WAF 服务器。
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|--------------------------|---------------|-----|-------|--------------------------------------------|
| nodes | array(object) | 必选 | | 长亭 WAF 的地址列表。 |
| nodes[0].host | string | 必选 | | 长亭 WAF 的地址,支持 IPV4、IPV6、Unix Socket 等配置方式。 |
| nodes[0].port | string | 可选 | 80 | 长亭 WAF 的端口。 |
| config | object | 否 | | 长亭 WAF 服务的配置参数值。当路由没有配置时将使用这里所配置的参数。 |
| config.connect_timeout | integer | 否 | 1000 | connect timeout, 毫秒 |
| config.send_timeout | integer | 否 | 1000 | send timeout, 毫秒 |
| config.read_timeout | integer | 否 | 1000 | read timeout, 毫秒 |
| config.req_body_size | integer | 否 | 1024 | 请求体大小,单位为 KB |
| config.keepalive_size | integer | 否 | 256 | 长亭 WAF 服务的最大并发空闲连接数 |
| config.keepalive_timeout | integer | 否 | 60000 | 空闲链接超时,毫秒 |
一个典型的示例配置如下:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```bash
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf -H "X-API-KEY: $admin_key" -X PUT -d '
{
"nodes":[
{
"host": "unix:/path/to/safeline/resources/detector/snserver.sock",
"port": 8000
}
]
}'
```
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|--------------------------|---------------|-----|-------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| match | array[object] | 否 | | 匹配规则列表,默认为空且规则将被无条件执行。 |
| match.vars | array[array] | 否 | | 由一个或多个 `{var, operator, val}` 元素组成的列表,例如:`{"arg_name", "==", "json"}`,表示当前请求参数 `name``json`。这里的 `var` 与 NGINX 内部自身变量命名是保持一致,所以也可以使用 `request_uri``host` 等;对于已支持的运算符,具体用法请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)`operator-list` 部分。 |
| append_waf_resp_header | bool | 否 | true | 是否添加响应头 |
| append_waf_debug_header | bool | 否 | false | 是否添加调试用响应头,`add_header``true` 时才生效 |
| config | object | 否 | | 长亭 WAF 服务的配置参数值。当路由没有配置时将使用元数据里所配置的参数。 |
| config.connect_timeout | integer | 否 | | connect timeout, 毫秒 |
| config.send_timeout | integer | 否 | | send timeout, 毫秒 |
| config.read_timeout | integer | 否 | | read timeout, 毫秒 |
| config.req_body_size | integer | 否 | | 请求体大小,单位为 KB |
| config.keepalive_size | integer | 否 | | 长亭 WAF 服务的最大并发空闲连接数 |
| config.keepalive_timeout | integer | 否 | | 空闲链接超时,毫秒 |
一个典型的示例配置如下,这里使用 `httpbun.org` 作为示例后端,可以按需替换:
```bash
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/*",
"plugins": {
"chaitin-waf": {
"match": [
{
"vars": [
["http_waf","==","true"]
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbun.org:80": 1
}
}
}'
```
## 测试插件
以上述的示例配置为例进行测试。
不满足匹配条件时,请求可以正常触达:
```bash
curl -H "Host: httpbun.org" http://127.0.0.1:9080/get -i
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 408
Connection: keep-alive
X-APISIX-CHAITIN-WAF: no
Date: Wed, 19 Jul 2023 09:30:42 GMT
X-Powered-By: httpbun/3c0dc05883dd9212ac38b04705037d50b02f2596
Server: APISIX/3.3.0
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbun.org",
"User-Agent": "curl/8.1.2",
"X-Forwarded-For": "127.0.0.1",
"X-Forwarded-Host": "httpbun.org",
"X-Forwarded-Port": "9080",
"X-Forwarded-Proto": "http",
"X-Real-Ip": "127.0.0.1"
},
"method": "GET",
"origin": "127.0.0.1, 122.231.76.178",
"url": "http://httpbun.org/get"
}
```
面对潜在的注入请求也原样转发并遇到 404 错误:
```bash
curl -H "Host: httpbun.org" http://127.0.0.1:9080/getid=1%20AND%201=1 -i
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
Content-Length: 19
Connection: keep-alive
X-APISIX-CHAITIN-WAF: no
Date: Wed, 19 Jul 2023 09:30:28 GMT
X-Content-Type-Options: nosniff
X-Powered-By: httpbun/3c0dc05883dd9212ac38b04705037d50b02f2596
Server: APISIX/3.3.0
404 page not found
```
当满足匹配条件时,正常请求依然可以触达上游:
```bash
curl -H "Host: httpbun.org" -H "waf: true" http://127.0.0.1:9080/get -i
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 427
Connection: keep-alive
X-APISIX-CHAITIN-WAF-TIME: 2
X-APISIX-CHAITIN-WAF-STATUS: 200
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-ACTION: pass
Date: Wed, 19 Jul 2023 09:29:58 GMT
X-Powered-By: httpbun/3c0dc05883dd9212ac38b04705037d50b02f2596
Server: APISIX/3.3.0
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbun.org",
"User-Agent": "curl/8.1.2",
"Waf": "true",
"X-Forwarded-For": "127.0.0.1",
"X-Forwarded-Host": "httpbun.org",
"X-Forwarded-Port": "9080",
"X-Forwarded-Proto": "http",
"X-Real-Ip": "127.0.0.1"
},
"method": "GET",
"origin": "127.0.0.1, 122.231.76.178",
"url": "http://httpbun.org/get"
}
```
而潜在的攻击请求将会被拦截并返回 403 错误:
```bash
curl -H "Host: httpbun.org" -H "waf: true" http://127.0.0.1:9080/getid=1%20AND%201=1 -i
HTTP/1.1 403 Forbidden
Date: Wed, 19 Jul 2023 09:29:06 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-TIME: 2
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF-STATUS: 403
Server: APISIX/3.3.0
Set-Cookie: sl-session=UdywdGL+uGS7q8xMfnJlbQ==; Domain=; Path=/; Max-Age=86400
{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "51a268653f2c4189bfa3ec66afbcb26d"}
```
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```bash
$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbun.org:80": 1
}
}
}'
```

View File

@@ -0,0 +1,209 @@
---
title: clickhouse-logger
keywords:
- APISIX
- API 网关
- Plugin
- ClickHouse
description: 本文介绍了 API 网关 Apache APISIX 如何使用 clickhouse-logger 插件将日志数据发送到 ClickHouse 数据库中。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`clickhouse-logger` 插件可用于将日志数据推送到 [ClickHouse](https://github.com/ClickHouse/ClickHouse) 数据库中。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------------- | ----------- | -------------------------------------------------------- |
| endpoint_addr | 废弃 | 是 | | | ClickHouse 的 `endpoints`。请使用 `endpoint_addrs` 代替。 |
| endpoint_addrs | array | 是 | | | ClickHouse 的 `endpoints。`。 |
| database | string | 是 | | | 使用的数据库。 |
| logtable | string | 是 | | | 写入的表名。 |
| user | string | 是 | | | ClickHouse 的用户。 |
| password | string | 是 | | | ClickHouse 的密码。 |
| timeout | integer | 否 | 3 | [1,...] | 发送请求后保持连接活动的时间。 |
| name | string | 否 | "clickhouse logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| ssl_verify | boolean | 否 | true | [true,false] | 当设置为 `true` 时,验证证书。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含请求体。**注意**:如果请求体无法完全存放在内存中,由于 NGINX 的限制APISIX 无法将它记录下来。|
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时进行过滤。只有当此处设置的表达式计算结果为 `true` 时,才会记录请求体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
| include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤。只有当此处设置的表达式计算结果为 `true` 时才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。|
注意schema 中还定义了 `encrypt_fields = {"password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"response": {
"status": 200,
"size": 118,
"headers": {
"content-type": "text/plain",
"connection": "close",
"server": "APISIX/3.7.0",
"content-length": "12"
}
},
"client_ip": "127.0.0.1",
"upstream_latency": 3,
"apisix_latency": 98.999998092651,
"upstream": "127.0.0.1:1982",
"latency": 101.99999809265,
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"route_id": "1",
"start_time": 1704507612177,
"service_id": "",
"request": {
"method": "POST",
"querystring": {
"foo": "unknown"
},
"headers": {
"host": "localhost",
"connection": "close",
"content-length": "18"
},
"size": 110,
"uri": "/hello?foo=unknown",
"url": "http://localhost:1984/hello?foo=unknown"
}
}
```
## 配置插件元数据
`clickhouse-logger` 也支持自定义日志格式,与 [http-logger](./http-logger.md) 插件类似。
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX](../apisix-variable.md)[NGINX](http://nginx.org/en/docs/varindex.html) 变量。该配置全局生效。如果你指定了 `log_format`,该配置就会对所有绑定 `clickhouse-logger` 的路由或服务生效。|
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/clickhouse-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
您可以使用 Clickhouse docker 镜像来创建一个容器,如下所示:
```shell
docker run -d -p 8123:8123 -p 9000:9000 -p 9009:9009 --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server
```
然后在您的 ClickHouse 数据库中创建一个表来存储日志。
```shell
curl -X POST 'http://localhost:8123/' \
--data-binary 'CREATE TABLE default.test (host String, client_ip String, route_id String, service_id String, `@timestamp` String, PRIMARY KEY(`@timestamp`)) ENGINE = MergeTree()' --user default:
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "",
"database": "default",
"logtable": "test",
"endpoint_addrs": ["http://127.0.0.1:8123"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
:::note 注意
如果配置多个 `endpoints`,日志将会随机写入到各个 `endpoints`
:::
## 测试插件
现在你可以向 APISIX 发起请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
现在,如果您检查表中的行,您将获得以下输出:
```shell
curl 'http://localhost:8123/?query=select%20*%20from%20default.test'
127.0.0.1 127.0.0.1 1 2023-05-08T19:15:53+05:30
```
## 删除插件
当你需要删除该插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,116 @@
---
title: client-control
keywords:
- APISIX
- API 网关
- Client Control
description: 本文介绍了 Apache APISIX proxy-control 插件的相关操作,你可以使用此插件动态地控制 NGINX 处理客户端的请求的行为。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`client-control` 插件能够通过设置客户端请求体大小的上限来动态地控制 NGINX 处理客户端的请求。
:::info 重要
此插件需要 APISIX 在 [APISIX-Runtime](../FAQ.md#如何构建-apisix-Runtime-环境) 环境上运行。更多信息请参考 [apisix-build-tools](https://github.com/api7/apisix-build-tools)
:::
## 属性
| 名称 | 类型 | 必选项 | 有效值 | 描述 |
| --------- | ------------- | ----------- | ------------------------------------------------------------------------ |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| max_body_size | integer | 否 | [0,...] | 设置客户端请求体的最大上限,动态调整 [`client_max_body_size`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) 的大小,单位为字节。当设置 `max_body_size` 为 0 时,将不会对客户端请求体大小进行检查。 |
## 启用插件
以下示例展示了如何在指定路由上启用 `client-control` 插件,并设置 `max_body_size`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"client-control": {
"max_body_size" : 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
启用插件后,使用 `curl` 命令请求该路由:
```shell
curl -i http://127.0.0.1:9080/index.html -d '123'
```
因为在配置插件时设置了 `max_body_size``1`,所以返回的 HTTP 响应头中如果带有 `413` 状态码,则表示插件生效:
```shell
HTTP/1.1 413 Request Entity Too Large
...
<html>
<head><title>413 Request Entity Too Large</title></head>
<body>
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>openresty</center>
</body>
</html>
```
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,353 @@
---
title: consumer-restriction
keywords:
- Apache APISIX
- API 网关
- Consumer restriction
description: Consumer Restriction 插件允许用户根据 Route、Service、Consumer 或 Consumer Group 来设置相应的访问限制。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`consumer-restriction` 插件允许用户根据 Route、Service、Consumer 或 Consumer Group 来设置相应的访问限制。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| -------------------------- | ------------- | ------ | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| type | string | 否 | consumer_name | ["consumer_name", "consumer_group_id", "service_id", "route_id"] | 支持设置访问限制的对象类型。 |
| whitelist | array[string] | 是 | | | 加入白名单的对象,优先级高于`allowed_by_methods`。 |
| blacklist | array[string] | 是 | | | 加入黑名单的对象,优先级高于`whitelist`。 |
| rejected_code | integer | 否 | 403 | [200,...] | 当请求被拒绝时,返回的 HTTP 状态码。 |
| rejected_msg | string | 否 | | | 当请求被拒绝时,返回的错误信息。 |
| allowed_by_methods | array[object] | 否 | | | 一组为 Consumer 设置允许的配置,包括用户名和允许的 HTTP 方法列表。 |
| allowed_by_methods.user | string | 否 | | | 为 Consumer 设置的用户名。 |
| allowed_by_methods.methods | array[string] | 否 | | ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE", "PURGE"] | 为 Consumer 设置的允许的 HTTP 方法列表。 |
:::note
不同的 `type` 属性值分别代表以下含义:
- `consumer_name`:把 Consumer 的 `username` 列入白名单或黑名单来限制 Consumer 对 Route 或 Service 的访问。
- `consumer_group_id`: 把 Consumer Group 的 `id` 列入白名单或黑名单来限制 Consumer 对 Route 或 Service 的访问。
- `service_id`:把 Service 的 `id` 列入白名单或黑名单来限制 Consumer 对 Service 的访问,需要结合授权插件一起使用。
- `route_id`:把 Route 的 `id` 列入白名单或黑名单来限制 Consumer 对 Route 的访问。
:::
## 启用并测试插件
### 通过 `consumer_name` 限制访问
首先,创建两个 Consumer分别为 `jack1``jack2`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -i -d '
{
"username": "jack1",
"plugins": {
"basic-auth": {
"username":"jack2019",
"password": "123456"
}
}
}'
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -i -d '
{
"username": "jack2",
"plugins": {
"basic-auth": {
"username":"jack2020",
"password": "123456"
}
}
}'
```
然后,在指定路由上启用并配置 `consumer-restriction` 插件,并通过将 `consumer_name` 加入 `whitelist` 来限制不同 Consumer 的访问:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"basic-auth": {},
"consumer-restriction": {
"whitelist": [
"jack1"
]
}
}
}'
```
**测试插件**
`jack1` 发出访问请求,返回 `200` HTTP 状态码,代表访问成功:
```shell
curl -u jack2019:123456 http://127.0.0.1:9080/index.html -i
```
```shell
HTTP/1.1 200 OK
```
`jack2` 发出访问请求,返回 `403` HTTP 状态码,代表访问被限制,插件生效:
```shell
curl -u jack2020:123456 http://127.0.0.1:9080/index.html -i
```
```shell
HTTP/1.1 403 Forbidden
...
{"message":"The consumer_name is forbidden."}
```
### 通过 `allowed_by_methods` 限制访问
首先,创建两个 Consumer分别为 `jack1``jack2`,创建方法请参考[通过 `consumer_name` 限制访问](#通过-consumername-限制访问)
然后,在指定路由上启用并配置 `consumer-restriction` 插件,并且仅允许 `jack1` 使用 `POST` 方法进行访问:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"basic-auth": {},
"consumer-restriction": {
"allowed_by_methods":[{
"user": "jack1",
"methods": ["POST"]
}]
}
}
}'
```
**测试插件**
`jack1` 发出访问请求,返回 `403` HTTP 状态码,代表访问被限制:
```shell
curl -u jack2019:123456 http://127.0.0.1:9080/index.html
```
```shell
HTTP/1.1 403 Forbidden
...
{"message":"The consumer_name is forbidden."}
```
现在更新插件配置,增加 `jack1``GET` 访问能力:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"basic-auth": {},
"consumer-restriction": {
"allowed_by_methods":[{
"user": "jack1",
"methods": ["POST","GET"]
}]
}
}
}'
```
`jack1` 再次发出访问请求,返回 `200` HTTP 状态码,代表访问成功:
```shell
curl -u jack2019:123456 http://127.0.0.1:9080/index.html
```
```shell
HTTP/1.1 200 OK
```
### 通过 `service_id` 限制访问
使用 `service_id` 的方式需要与授权插件一起配合使用,这里以 [`key-auth`](./key-auth.md) 授权插件为例。
首先,创建两个 Service
```shell
curl http://127.0.0.1:9180/apisix/admin/services/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"desc": "new service 001"
}'
curl http://127.0.0.1:9180/apisix/admin/services/2 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"desc": "new service 002"
}'
```
在指定 Consumer 上配置 `key-auth``consumer-restriction` 插件,并通过将 `service_id` 加入 `whitelist` 来限制 Consumer 对 Service 的访问:
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d '
{
"username": "new_consumer",
"plugins": {
"key-auth": {
"key": "auth-jack"
},
"consumer-restriction": {
"type": "service_id",
"whitelist": [
"1"
],
"rejected_code": 403
}
}
}'
```
**测试插件**
在指定路由上启用并配置 `key-auth` 插件,并绑定 `service_id``1`
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"service_id": 1,
"plugins": {
"key-auth": {
}
}
}'
```
对 Service 发出访问请求,返回 `403` HTTP 状态码,说明在白名单列中的 `service_id` 允许访问,插件生效:
```shell
curl http://127.0.0.1:9080/index.html -H 'apikey: auth-jack' -i
```
```shell
HTTP/1.1 200 OK
```
更新配置 `key-auth` 插件,并绑定 `service_id``2`
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"service_id": 2,
"plugins": {
"key-auth": {
}
}
}'
```
再次对 Service 发出访问请求,返回 `403` HTTP 状态码,说明不在白名单列表的 `service_id` 被拒绝访问,插件生效:
```shell
curl http://127.0.0.1:9080/index.html -H 'apikey: auth-jack' -i
```
```shell
HTTP/1.1 403 Forbidden
...
{"message":"The service_id is forbidden."}
```
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"basic-auth": {}
}
}'
```

View File

@@ -0,0 +1,127 @@
---
title: cors
keywords:
- Apache APISIX
- API 网关
- CORS
description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`cors` 插件可以让你轻松地为服务端启用 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)Cross-Origin Resource Sharing跨域资源共享的返回头。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ---------------- | ------- | ------ | ------ | ------------------------------------------------------------ |
| allow_origins | string | 否 | "*" | 允许跨域访问的 Origin格式为 `scheme://host:port`,示例如 `https://somedomain.com:8081`。如果你有多个 Origin请使用 `,` 分隔。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Origin 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Origin 均通过,但请注意这样存在安全隐患。 |
| allow_methods | string | 否 | "*" | 允许跨域访问的 Method比如`GET``POST` 等。如果你有多个 Method请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Method 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。 |
| allow_headers | string | 否 | "*" | 允许跨域访问时请求方携带哪些非 `CORS 规范` 以外的 Header。如果你有多个 Header请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Header 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Header 都通过,但请注意这样存在安全隐患。 |
| expose_headers | string | 否 | | 允许跨域访问时响应方携带哪些非 CORS 规范 以外的 Header。如果你有多个 Header请使用 , 分割。当 allow_credential 为 false 时,可以使用 * 来表示允许任意 Header。如果不设置插件不会修改 `Access-Control-Expose-Headers` 头,详情请参考 [Access-Control-Expose-Headers - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)。 |
| max_age | integer | 否 | 5 | 浏览器缓存 CORS 结果的最大时间,单位为秒。在这个时间范围内,浏览器会复用上一次的检查结果,`-1` 表示不缓存。请注意各个浏览器允许的最大时间不同,详情请参考 [Access-Control-Max-Age - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#directives)。 |
| allow_credential | boolean | 否 | false | 是否允许跨域访问的请求方携带凭据(如 Cookie 等)。根据 CORS 规范,如果设置该选项为 `true`,那么将不能在其他属性中使用 `*`。 |
| allow_origins_by_regex | array | 否 | nil | 使用正则表达式数组来匹配允许跨域访问的 Origin`[".*\.test.com$"]` 可以匹配任何 `test.com` 的子域名。如果 `allow_origins_by_regex` 属性已经指定,则会忽略 `allow_origins` 属性。 |
| allow_origins_by_metadata | array | 否 | nil | 通过引用插件元数据的 `allow_origins` 配置允许跨域访问的 Origin。比如当插件元数据为 `"allow_origins": {"EXAMPLE": "https://example.com"}` 时,配置 `["EXAMPLE"]` 将允许 Origin `https://example.com` 的访问。 |
:::info IMPORTANT
1. `allow_credential` 是一个很敏感的选项,请谨慎开启。开启之后,其他参数默认的 `*` 将失效,你必须显式指定它们的值。
2. 在使用 `**` 时,需要清楚该参数引入的一些安全隐患,比如 CSRF并确保这样的安全等级符合自己预期。
:::
## 元数据
| 名称 | 类型 | 必选项 | 描述 |
| ----------- | ------ | ------ | ------------------ |
| allow_origins | object | 否 | 定义允许跨域访问的 Origin它的键为 `allow_origins_by_metadata` 使用的引用键,值则为允许跨域访问的 Origin其语义与属性中的 `allow_origins` 相同。 |
## 启用插件
你可以在路由或服务上启用 `cors` 插件。
你可以通过如下命令在指定路由上启用 `cors` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {
"cors": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl http://127.0.0.1:9080/hello -v
```
如果返回结果中出现 CORS 相关的 header则代表插件生效
```shell
...
< Server: APISIX web server
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: *
< Access-Control-Allow-Headers: *
< Access-Control-Max-Age: 5
...
```
## 删除插件
当你需要禁用 `cors` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
```

View File

@@ -0,0 +1,155 @@
---
title: csrf
keywords:
- Apache APISIX
- API 网关
- 跨站请求伪造攻击
- Cross-site request forgery
- csrf
description: CSRF 插件基于 Double Submit Cookie 的方式,帮助用户阻止跨站请求伪造攻击。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`csrf` 插件基于 [`Double Submit Cookie`](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Double_Submit_Cookie) 的方式,保护用户的 API 免于 CSRF 攻击。
在此插件运行时,`GET``HEAD``OPTIONS` 会被定义为 `safe-methods`,其他的请求方法则定义为 `unsafe-methods`。因此 `GET``HEAD``OPTIONS` 方法的调用不会被检查拦截。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ----------- | ------- | ----- |---------------------|
| name | string | 否 | `apisix-csrf-token` | | 生成的 Cookie 中的 Token 名称,需要使用此名称在请求头携带 Cookie 中的内容。 |
| expires | number | 否 | `7200` | | CSRF Cookie 的过期时间,单位为秒。当设置为 `0` 时,会忽略 CSRF Cookie 过期时间检查。|
| key | string | 是 | | | 加密 Token 的密钥。 |
注意schema 中还定义了 `encrypt_fields = {"key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
## 启用插件
以下示例展示了如何在指定路由上启用并配置 `csrf` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {
"csrf": {
"key": "edd1c9f034335f136f87ad84b625c8f1"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
}
}'
```
当你使用 `GET` 之外的方法访问被保护的路由时,请求会被拦截并返回 `401` HTTP 状态码。
使用 `GET` 请求 `/hello` 时,在响应中会有一个携带了加密 Token 的 Cookie。Token 字段名称为插件配置中的 `name` 值,默认为 `apisix-csrf-token`
:::note
每一个请求都会返回一个新的 Cookie。
:::
在后续对该路由进行的 `unsafe-methods` 请求中,需要从 Cookie 中读取加密的 Token并在请求头中携带该 Token。请求头字段的名称为插件属性中的 `name`
## 测试插件
启用插件后,使用 `curl` 命令尝试直接对该路由发起 `POST` 请求,会返回 `Unauthorized` 字样的报错提示:
```shell
curl -i http://127.0.0.1:9080/hello -X POST
```
```shell
HTTP/1.1 401 Unauthorized
...
{"error_msg":"no csrf token in headers"}
```
当发起 `GET` 请求时,返回结果中会有携带 Token 的 Cookie
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
Set-Cookie: apisix-csrf-token=eyJyYW5kb20iOjAuNjg4OTcyMzA4ODM1NDMsImV4cGlyZXMiOjcyMDAsInNpZ24iOiJcL09uZEF4WUZDZGYwSnBiNDlKREtnbzVoYkJjbzhkS0JRZXVDQm44MG9ldz0ifQ==;path=/;Expires=Mon, 13-Dec-21 09:33:55 GMT
```
在请求之前,用户需要从 Cookie 中读取 Token并在后续的 `unsafe-methods` 请求的请求头中携带。
例如,你可以在客户端使用 [js-cookie](https://github.com/js-cookie/js-cookie) 读取 Cookie使用 [axios](https://github.com/axios/axios) 发送请求:
```js
const token = Cookie.get('apisix-csrf-token');
const instance = axios.create({
headers: {'apisix-csrf-token': token}
});
```
使用 `curl` 命令发送请求,确保请求中携带了 Cookie 信息,如果返回 `200` HTTP 状态码则表示请求成功:
```shell
curl -i http://127.0.0.1:9080/hello -X POST -H 'apisix-csrf-token: eyJyYW5kb20iOjAuNjg4OTcyMzA4ODM1NDMsImV4cGlyZXMiOjcyMDAsInNpZ24iOiJcL09uZEF4WUZDZGYwSnBiNDlKREtnbzVoYkJjbzhkS0JRZXVDQm44MG9ldz0ifQ==' -b 'apisix-csrf-token=eyJyYW5kb20iOjAuNjg4OTcyMzA4ODM1NDMsImV4cGlyZXMiOjcyMDAsInNpZ24iOiJcL09uZEF4WUZDZGYwSnBiNDlKREtnbzVoYkJjbzhkS0JRZXVDQm44MG9ldz0ifQ=='
```
```shell
HTTP/1.1 200 OK
```
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,210 @@
---
title: datadog
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 简介
`datadog` 是 Apache APISIX 内置的监控插件,可与 [Datadog](https://www.datadoghq.com/)(云应用最常用的监控和可观测性平台之一)无缝集成。`datadog` 插件支持对每个请求和响应周期进行多种指标参数的获取,这些指标参数基本反映了系统的行为和健康状况。
`datadog` 插件通过 UDP 协议将其自定义指标推送给 DogStatsD 服务器,该服务器通过 UDP 连接与 Datadog Agent 捆绑在一起(关于如何安装 Datadog Agent请参考[Agent](https://docs.datadoghq.com/agent/) 。DogStatsD 基本上是 StatsD 协议的实现,它为 Apache APISIX Agent 收集自定义指标,并将其聚合成单个数据点,发送到配置的 Datadog 服务器。更多关于 DogStatsD 的信息,请参考 [DogStatsD](https://docs.datadoghq.com/developers/dogstatsd/?tab=hostagent)
`datadog` 插件具有将多个指标参数组成一个批处理统一推送给外部 Datadog Agent 的能力,并且可以重复使用同一个数据包套接字。
此功能可以有效解决日志数据发送不及时的问题。在创建批处理器之后,如果对 `inactive_timeout` 参数进行配置,那么批处理器会在配置好的时间内自动发送日志数据。如果不进行配置,时间默认为 5s。
关于 Apache APISIX 的批处理程序的更多信息,请参考 [Batch-Processor](../batch-processor.md#配置)
## APISIX-Datadog plugin 工作原理
![APISIX-Datadog 插件架构图](https://static.apiseven.com/202108/1636685752757-d02d8305-2a68-4b3e-b2cc-9e5410c8bf11.png)
APISIX-Datadog 插件将其自定义指标推送到 DogStatsD server。而 DogStatsD server 通过 UDP 连接与 Datadog agent 捆绑在一起。DogStatsD 是 StatsD 协议的一个实现。它为 Apache APISIX agent 收集自定义指标,将其聚合成一个数据点,并将其发送到配置的 Datadog server。要了解更多关于 DogStatsD 的信息,请访问 DogStatsD 文档。
当你启用 APISIX-Datadog 插件时Apache APISIX agent 会在每个请求响应周期向 DogStatsD server 输出以下指标:
| 参数名称 | StatsD 类型 | 描述 |
| ---------------- | ----------- | ---------------------------------------------------------- |
| Request Counter | Counter | 收到的请求数量。 |
| Request Latency | Histogram | 处理该请求所需的时间,以毫秒为单位。 |
| Upstream latency | Histogram | 上游 server agent 请求到收到响应所需的时间,以毫秒为单位。 |
| APISIX Latency | Histogram | APISIX agent 处理该请求的时间,以毫秒为单位。 |
| Ingress Size | Timer | 请求体大小,以字节为单位。 |
| Egress Size | Timer | 响应体大小,以字节为单位。 |
这些指标将被发送到 DogStatsD agent并带有以下标签。如果任何特定的标签没有合适的值该标签将被直接省略。
| 参数名称 | 描述 |
| --------------- | ------------------------------------------------------------ |
| route_name | 路由的名称,如果不存在,将显示路由 ID。 |
| service_id | 如果一个路由是用服务的抽象概念创建的,那么特定的服务 ID 将被使用。 |
| consumer | 如果路由有一个链接的消费者,消费者的用户名将被添加为一个标签。 |
| balancer_ip | 处理了当前请求的上游复制均衡器的的 IP。 |
| response_status | HTTP 响应状态代码。 |
| scheme | 已用于提出请求的协议,如 HTTP、gRPC、gRPCs 等。 |
APISIX-Datadog 插件维护了一个带有 timer 的 buffer。当 timer 失效时APISIX-Datadog 插件会将 buffer 的指标作为一个批量处理程序传送给本地运行的 DogStatsD server。这种方法通过重复使用相同的 UDP 套接字,对资源的占用较少,而且由于可以配置 timer所以不会一直让网络过载。
## 如何使用插件
### 前提Datadog Agent
1. 首先你必须在系统中安装一个 Datadog agent。它可以是一个 docker 容器,一个 pod 或是一个二进制的包管理器。你只需要确保 Apache APISIX agent 可以到达 Datadog agent 的 8125 端口。
2. 如果你从没使用过 Datadog
1. 首先访问 [www.datadoghq.com](http://www.datadoghq.com/) ,创建一个账户。
2. 然后按照下图标注的步骤生成 API 密钥。 ![Generate an API Key](https://static.apiseven.com/202108/1636685007445-05f134fd-e80a-4173-b1d7-f0a118087998.png)
3. APISIX-Datadog 插件只需要依赖 `datadog/agent` 的 dogstatsd 组件即可实现,因为该插件按照 statsd 协议通过标准的 UDP 套接字向 DogStatsD server 异步发送参数。我们推荐使用独立的 `datadog/dogstatsd` 镜像,而不是使用完整的`datadog/agent` ,因为 `datadog/dogstatsd` 的组件大小只有大约 11 MB更加轻量化。而完整的 `datadog/agent` 镜像的大小为 2.8 GB。
运行以下命令,将它作为一个容器来运行:
```shell
# pull the latest image
docker pull datadog/dogstatsd:latest
# run a detached container
docker run -d --name dogstatsd-agent -e DD_API_KEY=<Your API Key from step 2> -p 8125:8125/udp datadog/dogstatsd
```
如果你在生产环境中使用 Kubernetes你可以将 `dogstatsd` 作为一个 `Daemonset``Multi-Container Pod` 与 Apache APISIX agent 一起部署。
### 启用插件
本小节介绍了如何在指定路由上启用 `datadog` 插件。进行以下操作之前请确认您的 Datadog Agent 已经启动并正常运行。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"datadog": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
现在,任何对 uri `/hello` 的请求都会生成上述指标,并推送到 Datadog Agent 的 DogStatsD 服务器。
### 删除插件
删除插件配置中相应的 JSON 配置以禁用 `datadog`
APISIX 插件是支持热加载的,所以不用重新启动 APISIX配置就能生效。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
### 补充:自定义配置
在默认配置中,`datadog` 插件希望 Dogstatsd 服务在 `127.0.0.1:8125` 可用。如果你想更新配置,请更新插件的元数据。如果想要了解更多关于 `datadog` 插件元数据的字段,请参阅[元数据](#元数据)
`/apisix/admin/plugin_metadata/datadog` 发起请求,更改其元数据。操作示例如下:
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/datadog -H "X-API-KEY: $admin_key" -X PUT -d '
{
"host": "172.168.45.29",
"port": 8126,
"constant_tags": [
"source:apisix",
"service:custom"
],
"namespace": "apisix"
}'
```
上述命令将会更新元数据,后续各指标将通过 UDP StatsD 推送到 `172.168.45.29:8126` 上对应的服务,并且配置将被热加载,不需要重新启动 APISIX 实例,就可以使配置生效。
如果你想把 `datadog` 插件的元数据 schema 恢复到默认值,只需向同一个服务地址再发出一个 Body 为空的 PUT 请求。示例如下:
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/datadog \
-H "X-API-KEY: $admin_key" -X PUT -d '{}'
```
## 配置属性
### 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------- | ------ | ----------- | ------- | ----- | ------------------------------------------------------------ |
| prefer_name | boolean | optional | true | true/false | 如果设置为 `false`,将使用路由/服务的 id 值作为插件的 `route_name`,而不是带有参数的标签名称。 |
该插件支持使用批处理程序来聚集和处理条目(日志/数据)的批次。这就避免了插件频繁地提交数据,默认情况下,批处理程序每 `5` 秒或当队列中的数据达到 `1000` 时提交数据。有关信息或自定义批处理程序的参数设置,请参阅[批处理程序](../batch-processor.md#configuration) 配置部分。
### 元数据
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ----------- | ------ | ----------- | ------- | ---------------------------------------------------------------------- |
| host | string | optional | "127.0.0.1" | DogStatsD 服务器的主机地址 |
| port | integer | optional | 8125 | DogStatsD 服务器的主机端口 |
| namespace | string | optional | "apisix" | 由 APISIX 代理发送的所有自定义参数的前缀。对寻找指标图的实体很有帮助例如apisix.request.counter。 |
| constant_tags | array | optional | [ "source:apisix" ] | 静态标签嵌入到生成的指标中。这对某些信号的度量进行分组很有用。 |
要了解更多关于如何有效地编写标签,请访问[这里](https://docs.datadoghq.com/getting_started/tagging/#defining-tags)
### 输出指标
启用 datadog 插件之后APISIX 就会按照下面的指标格式,将数据整理成数据包最终发送到 DogStatsD server。
| Metric Name | StatsD Type | Description |
| ----------- | ----------- | ------- |
| Request Counter | Counter | 收到的请求数量。 |
| Request Latency | Histogram | 处理该请求所需的时间(以毫秒为单位)。 |
| Upstream latency | Histogram | 代理请求到上游服务器直到收到响应所需的时间(以毫秒为单位)。 |
| APISIX Latency | Histogram | APISIX 代理处理该请求的时间(以毫秒为单位)。|
| Ingress Size | Timer | 以字节为单位的请求体大小。 |
| Egress Size | Timer | 以字节为单位的响应体大小。 |
这些指标会带有以下标签,并首先被发送到本地 DogStatsD Agent。
> 如果一个标签没有合适的值,该标签将被直接省略。
- **route_name**:在路由模式定义中指定的名称,如果不存在或插件属性 `prefer_name` 被设置为 `false`,它将默认使用路由/服务的 id 值。
- **service_name**:如果一个路由是用服务的抽象概念创建的,特定的服务 name/id基于插件的 `prefer_name` 属性)将被使用。
- **consumer**:如果路由有一个正在链接中的消费者,那么消费者的用户名将被添加为一个标签。
- **balancer_ip**:处理当前请求的上游负载均衡器的 IP。
- **response_status**HTTP 响应状态代码。
- **scheme**:已用于提出请求的协议,如 HTTP、gRPC、gRPCs 等。

View File

@@ -0,0 +1,156 @@
---
title: dubbo-proxy
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`dubbo-proxy` 插件允许将 `HTTP` 请求代理到 [**dubbo**](http://dubbo.apache.org)
## 要求
如果你正在使用 `OpenResty`, 你需要编译它来支持 `dubbo`, 参考 [APISIX-Runtime](../FAQ.md#如何构建-apisix-runtime-环境)
## 运行时属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------ | ------ | ----------- | -------- | ------------ | -------------------------------------------------------------------- |
| service_name | string | 必选 | | | dubbo 服务名字 |
| service_version | string | 必选 | | | dubbo 服务版本 |
| method | string | 可选 | uri 路径 | | dubbo 服务方法 |
## 静态属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------ | ------ | ----------- | -------- | ------------ | -------------------------------------------------------------------- |
| upstream_multiplex_count | number | 必选 | 32 | >= 1 | 上游连接中最大的多路复用请求数 |
## 如何启用
首先,在 `config.yaml` 中启用 `dubbo-proxy` 插件:
```
# Add this in config.yaml
plugins:
- ... # plugin you need
- dubbo-proxy
```
然后重载 `APISIX`
这里有个例子,在指定的路由中启用 `dubbo-proxy` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"nodes": {
"127.0.0.1:20880": 1
},
"type": "roundrobin"
}'
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uris": [
"/hello"
],
"plugins": {
"dubbo-proxy": {
"service_name": "org.apache.dubbo.sample.tengine.DemoService",
"service_version": "0.0.0",
"method": "tengineDubbo"
}
},
"upstream_id": 1
}'
```
## 测试插件
你可以在 `Tengine` 提供的 [快速开始](https://github.com/alibaba/tengine/tree/master/modules/mod_dubbo#quick-start) 例子中使用上述配置进行测试。
将会有同样的结果。
从上游 `dubbo` 服务返回的数据一定是 `Map<String, String>` 类型。
如果返回的数据如下
```json
{
"status": "200",
"header1": "value1",
"header2": "valu2",
"body": "blahblah"
}
```
则对应的 `HTTP` 响应如下
```http
HTTP/1.1 200 OK # "status" will be the status code
...
header1: value1
header2: value2
...
blahblah # "body" will be the body
```
## 删除插件
当你想在某个路由或服务中禁用 `dubbo-proxy` 插件,非常简单,你可以直接删除插件配置中的 `json` 配置,不需要重启服务就能立即生效:
```shell
$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uris": [
"/hello"
],
"plugins": {
},
"upstream_id": 1
}
}'
```
现在 `dubbo-proxy` 插件就已经被禁用了。此方法同样适用于其他插件。
如果你想彻底禁用 `dubbo-proxy` 插件,
你需要在 `config.yaml` 中注释掉以下内容:
```yaml
plugins:
- ... # plugin you need
#- dubbo-proxy
```
然后重新加载 `APISIX`

View File

@@ -0,0 +1,133 @@
---
title: echo
keywords:
- Apache APISIX
- API 网关
- Plugin
- Echo
description: 本文介绍了关于 Apache APISIX `echo` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`echo` 插件可以帮助用户尽可能地全面了解如何开发 APISIX 插件。
该插件展示了如何在常见的 `phase` 中实现相应的功能,常见的 `phase` 包括init, rewrite, access, balancer, header filter, body filter 以及 log。
:::caution WARNING
`echo` 插件只能用作示例,并不能处理一些特别的场景。**请勿将该插件用在生产环境中!**
:::
## 属性
| 名称 | 类型 | 必选项 | 描述 |
| ----------- | ------ | ------ | ----------------------------------------------------------------------------------------------- |
| before_body | string | 否 | 在 `body` 属性之前添加的内容,如果 `body` 属性没有指定,就会将其添加在上游 `response body` 之前。 |
| body | string | 否 | 返回给客户端的响应内容,它将覆盖上游返回的响应 `body`。 |
| after_body | string | 否 | 在 `body` 属性之后添加的内容,如果 body 属性没有指定将在上游响应 `body` 之后添加。 |
| headers | object | 否 | 返回值的 headers。 |
:::note
参数 `before_body``body``after_body` 至少要配置一个。
:::
## 启用插件
以下示例展示了如何在指定路由中启用 `echo` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"echo": {
"before_body": "before the body modification "
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
## 测试插件
通过上述命令启用插件后,你可以使用如下命令测试插件是否启用成功:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
before the body modification hello world
```
## 删除插件
当你需要禁用 `echo` 插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,446 @@
---
title: elasticsearch-logger
keywords:
- APISIX
- API 网关
- 插件
- Elasticsearch-logger
- 日志
description: elasticsearch-logger Plugin 将请求和响应日志批量推送到 Elasticsearch并支持日志格式的自定义。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/elasticsearch-logger" />
</head>
## 描述
`elasticsearch-logger` 插件将请求和响应日志批量推送到 [Elasticsearch](https://www.elastic.co),并支持自定义日志格式。启用后,插件会将请求上下文信息序列化为 [Elasticsearch Bulk 格式](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk) 并将其添加到队列中,然后再推送到 Elasticsearch。有关更多详细信息请参阅 [批处理器](../batch-processor.md)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ------------- | ------- | -------- | -------------------- | ------------------------------------------------------------ |
| endup_addrs | array[string] | 是 | | Elasticsearch API 端点地址。如果配置了多个端点,则会随机写入。 |
| field | object | 是 | | Elasticsearch `field` 配置。 |
| field.index | string | 是 | | Elasticsearch [_index 字段](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-index-field.html#mapping-index-field)。 |
| log_format | object | 否 | | JSON 格式的键值对中的自定义日志格式。值中支持 [APISIX](../apisix-variable.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html)。 |
| auth | array | 否 | | Elasticsearch [身份验证](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) 配置。 |
| auth.username | string | 是 | | Elasticsearch [身份验证](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) 用户名​​。 |
| auth.password | string | 是 | | Elasticsearch [身份验证](https://www.elastic.co/guide/en/elasticsearch/reference/current/setting-up-authentication.html) 密码。 |
| ssl_verify | boolean | 否 | true | 如果为 true则执行 SSL 验证。 |
| timeout | integer | 否 | 10 | Elasticsearch 发送数据超时(秒)。 |
| include_req_body | boolean | 否 | false |如果为 true则将请求主体包含在日志中。请注意如果请求主体太大而无法保存在内存中则由于 NGINX 的限制而无法记录。|
| include_req_body_expr | array[array] | 否 | | 一个或多个条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。在 `include_req_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录请求主体。|
| include_resp_body | boolean | 否 | false | 如果为 true则将响应主体包含在日志中。|
| include_resp_body_expr | array[array] | 否 | | 一个或多个条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。在 `include_resp_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录响应主体。|
注意schema 中还定义了 `encrypt_fields = {"auth.password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
本插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。
## Plugin Metadata
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| log_format | object | 否 | |自定义日志格式为 JSON 格式的键值对。值中支持 [APISIX 变量](../apisix-variable.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html)。 |
## 示例
以下示例演示了如何为不同场景配置 `elasticsearch-logger` 插件。
要遵循示例,请在 Docker 中启动 Elasticsearch 实例:
```shell
docker run -d \
--name elasticsearch \
--network apisix-quickstart-net \
-v elasticsearch_vol:/usr/share/elasticsearch/data/ \
-p 9200:9200 \
-p 9300:9300 \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
-e discovery.type=single-node \
-e xpack.security.enabled=false \
docker.elastic.co/elasticsearch/elasticsearch:7.17.1
```
在 Docker 中启动 Kibana 实例,以可视化 Elasticsearch 中的索引数据:
```shell
docker run -d \
--name kibana \
--network apisix-quickstart-net \
-p 5601:5601 \
-e ELASTICSEARCH_HOSTS="http://elasticsearch:9200" \
docker.elastic.co/kibana/kibana:7.17.1
```
如果成功,您应该在 [localhost:5601](http://localhost:5601) 上看到 Kibana 仪表板。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 以默认日志格式记录
以下示例演示如何在路由上启用 `elasticsearch-logger` 插件,该插件记录客户端对路由的请求和响应,并将日志推送到 Elasticsearch。
使用 `elasticsearch-logger` 创建路由,将 `index` 字段配置为 `gateway`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "elasticsearch-logger-route",
"uri": "/anything",
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway"
}
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
向路由发送请求以生成日志条目:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [localhost:5601](http://localhost:5601) 上的 Kibana 仪表板,并在 __Discover__ 选项卡下创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据。配置完成后,导航回 __Discover__ 选项卡,您应该会看到生成的日志,类似于以下内容:
```json
{
"_index": "gateway",
"_id": "CE-JL5QBOkdYRG7kEjTJ",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"host": "127.0.0.1:9080",
"accept": "*/*",
"user-agent": "curl/8.6.0"
},
"size": 85,
"querystring": {},
"method": "GET",
"url": "http://127.0.0.1:9080/anything",
"uri": "/anything"
},
"response": {
"headers": {
"content-type": "application/json",
"access-control-allow-credentials": "true",
"server": "APISIX/3.11.0",
"content-length": "390",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 10:18:14 GMT"
},
"status": 200,
"size": 618
},
"route_id": "elasticsearch-logger-route",
"latency": 585.00003814697,
"apisix_latency": 18.000038146973,
"upstream_latency": 567,
"upstream": "50.19.58.113:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}
```
### 使用 Plugin Metadata 记录请求和响应标头
以下示例演示了如何使用 [Plugin Metadata](../terminology/plugin-metadata.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html) 自定义日志格式,以记录请求和响应中的特定标头。
在 APISIX 中,[Plugin Metadata](../terminology/plugin-metadata.md) 用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并需要对其元数据字段进行通用更新时,它很有用。
首先,使用 `elasticsearch-logger` 创建路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "elasticsearch-logger-route",
"uri": "/anything",
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
接下来,配置 `elasticsearch-logger` 的 Plugin Metadata
```shell
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/elasticsearch-logger" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr",
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'
```
使用 `env` 标头向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -H "env: dev"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [localhost:5601](http://localhost:5601) 上的 Kibana 仪表板,并在 __Discover__ 选项卡下创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据(如果您尚未这样做)。配置完成后,导航回 __Discover__ 选项卡,您应该会看到生成的日志,类似于以下内容:
```json
{
"_index": "gateway",
"_id": "Ck-WL5QBOkdYRG7kODS0",
"_version": 1,
"_score": 1,
"_source": {
"client_ip": "192.168.65.1",
"route_id": "elasticsearch-logger-route",
"@timestamp": "2025-01-06T10:32:36+00:00",
"host": "127.0.0.1",
"resp_content_type": "application/json"
},
"fields": {
...
}
}
```
### 有条件地记录请求主体
以下示例演示了如何有条件地记录请求主体。
使用 `elasticsearch-logger` 创建路由,仅在 URL 查询字符串 `log_body``true` 时记录请求主体:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"elasticsearch-logger": {
"endpoint_addrs": ["http://elasticsearch:9200"],
"field": {
"index": "gateway"
},
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
},
"uri": "/anything",
"id": "elasticsearch-logger-route"
}'
```
使用满足以下条件的 URL 查询字符串向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [localhost:5601](http://localhost:5601) 上的 Kibana 仪表板,并在 __Discover__ 选项卡下创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据(如果您尚未这样做)。配置完成后,导航回 __Discover__ 选项卡,您应该会看到生成的日志,类似于以下内容:
```json
{
"_index": "gateway",
"_id": "Dk-cL5QBOkdYRG7k7DSW",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"user-agent": "curl/8.6.0",
"accept": "*/*",
"content-length": "14",
"host": "127.0.0.1:9080",
"content-type": "application/x-www-form-urlencoded"
},
"size": 182,
"querystring": {
"log_body": "yes"
},
"body": "{\"env\": \"dev\"}",
"method": "POST",
"url": "http://127.0.0.1:9080/anything?log_body=yes",
"uri": "/anything?log_body=yes"
},
"start_time": 1735965595203,
"response": {
"headers": {
"content-type": "application/json",
"server": "APISIX/3.11.0",
"access-control-allow-credentials": "true",
"content-length": "548",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 11:02:32 GMT"
},
"status": 200,
"size": 776
},
"route_id": "elasticsearch-logger-route",
"latency": 703.9999961853,
"apisix_latency": 34.999996185303,
"upstream_latency": 669,
"upstream": "34.197.122.172:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}
```
向路由发送一个没有任何 URL 查询字符串的请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'
```
导航到 Kibana 仪表板 __Discover__ 选项卡,您应该看到生成的日志,但没有请求正文:
```json
{
"_index": "gateway",
"_id": "EU-eL5QBOkdYRG7kUDST",
"_version": 1,
"_score": 1,
"_source": {
"request": {
"headers": {
"content-type": "application/x-www-form-urlencoded",
"accept": "*/*",
"content-length": "14",
"host": "127.0.0.1:9080",
"user-agent": "curl/8.6.0"
},
"size": 169,
"querystring": {},
"method": "POST",
"url": "http://127.0.0.1:9080/anything",
"uri": "/anything"
},
"start_time": 1735965686363,
"response": {
"headers": {
"content-type": "application/json",
"access-control-allow-credentials": "true",
"server": "APISIX/3.11.0",
"content-length": "510",
"access-control-allow-origin": "*",
"connection": "close",
"date": "Mon, 13 Jan 2025 11:15:54 GMT"
},
"status": 200,
"size": 738
},
"route_id": "elasticsearch-logger-route",
"latency": 680.99999427795,
"apisix_latency": 4.9999942779541,
"upstream_latency": 676,
"upstream": "34.197.122.172:80",
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"service_id": "",
"client_ip": "192.168.65.1"
},
"fields": {
...
}
}
```
:::info
如果您除了将 `include_req_body``include_resp_body` 设置为 `true` 之外还自定义了 `log_format`,则插件不会在日志中包含正文。
作为一种解决方法,您可以在日志格式中使用 NGINX 变量 `$request_body`,例如:
```json
{
"elasticsearch-logger": {
...,
"log_format": {"body": "$request_body"}
}
}
```
:::

View File

@@ -0,0 +1,192 @@
---
title: error-log-logger
keywords:
- APISIX
- API 网关
- 错误日志
- Plugin
description: API 网关 Apache APISIX error-log-logger 插件用于将 APISIX 的错误日志推送到 TCP、Apache SkyWalking、Apache Kafka 或 ClickHouse 服务器。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`error-log-logger` 插件用于将 APISIX 的错误日志 (`error.log`) 推送到 TCP、Apache SkyWalking、Apache Kafka 或 ClickHouse 服务器,你还可以设置错误日志级别以将日志发送到服务器。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| -------------------------------- | ------- | ------ | ------------------------------ | ------------- | -------------------------------------------------------------------------------- |
| tcp.host | string | 是 | | | TCP 服务的 IP 地址或主机名。 |
| tcp.port | integer | 是 | | [0,...] | 目标端口。 |
| tcp.tls | boolean | 否 | false | [false, true] | 当设置为 `true` 时执行 SSL 验证。 |
| tcp.tls_server_name | string | 否 | | | TLS 服务名称标记。 |
| skywalking.endpoint_addr | string | 否 | http://127.0.0.1:12900/v3/logs | | SkyWalking 的 HTTP endpoint 地址例如http://127.0.0.1:12800。 |
| skywalking.service_name | string | 否 | APISIX | | SkyWalking 上报的 service 名称。 |
| skywalking.service_instance_name | String | 否 | APISIX Instance Name | | SkyWalking 上报的 service 实例名,如果希望直接获取本机主机名请设置为 `$hostname`。 |
| clickhouse.endpoint_addr | String | 否 | http://127.0.0.1:8213 | | ClickHouse 的 HTTP endpoint 地址,例如 `http://127.0.0.1:8213`。 |
| clickhouse.user | String | 否 | default | | ClickHouse 的用户名。 |
| clickhouse.password | String | 否 | | | ClickHouse 的密码。 |
| clickhouse.database | String | 否 | | | ClickHouse 的用于接收日志的数据库。 |
| clickhouse.logtable | String | 否 | | | ClickHouse 的用于接收日志的表。 |
| kafka.brokers | array | 是 | | | 需要推送的 Kafka broker 列表。 |
| kafka.brokers.host | string | 是 | | | Kafka broker 的节点 host 配置,例如 `192.168.1.1`|
| kafka.brokers.port | string | 是 | | | Kafka broker 的节点端口配置 |
| kafka.brokers.sasl_config | object | 否 | | | Kafka broker 中的 sasl_config |
| kafka.brokers.sasl_config.mechanism | string | 否 | "PLAIN" | ["PLAIN"] | Kafka broker 中的 sasl 认证机制 |
| kafka.brokers.sasl_config.user | string | 是 | | | Kafka broker 中 sasl 配置中的 user如果 sasl_config 存在,则必须填写 |
| kafka.brokers.sasl_config.password | string | 是 | | | Kafka broker 中 sasl 配置中的 password如果 sasl_config 存在,则必须填写 |
| kafka.kafka_topic | string | 是 | | | 需要推送的 Kafka topic。|
| kafka.producer_type | string | 否 | async | ["async", "sync"] | 生产者发送消息的模式。|
| kafka.required_acks | integer | 否 | 1 | [0, 1, -1] | 生产者在确认一个请求发送完成之前需要收到的反馈信息的数量。该参数是为了保证发送请求的可靠性。该属性的配置与 Kafka `acks` 属性相同,具体配置请参考 [Apache Kafka 文档](https://kafka.apache.org/documentation/#producerconfigs_acks)。 |
| kafka.key | string | 否 | | | 用于消息分区而分配的密钥。 |
| kafka.cluster_name | integer | 否 | 1 | [0,...] | Kafka 集群的名称,当有两个及以上 Kafka 集群时使用。只有当 `producer_type` 设为 `async` 模式时才可以使用该属性。|
| kafka.meta_refresh_interval | integer | 否 | 30 | [1,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `refresh_interval` 参数,用于指定自动刷新 metadata 的间隔时长,单位为秒。 |
| timeout | integer | 否 | 3 | [1,...] | 连接和发送数据超时间,以秒为单位。 |
| keepalive | integer | 否 | 30 | [1,...] | 复用连接时,连接保持的时间,以秒为单位。 |
| level | string | 否 | WARN | | 进行错误日志筛选的级别,默认为 `WARN`,取值 ["STDERR", "EMERG", "ALERT", "CRIT", "ERR", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG"],其中 `ERR``ERROR` 级别一致。 |
注意schema 中还定义了 `encrypt_fields = {"clickhouse.password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
本插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。
### 默认日志格式示例
```text
["2024/01/06 16:04:30 [warn] 11786#9692271: *1 [lua] plugin.lua:205: load(): new plugins: {"error-log-logger":true}, context: init_worker_by_lua*","\n","2024/01/06 16:04:30 [warn] 11786#9692271: *1 [lua] plugin.lua:255: load_stream(): new plugins: {"limit-conn":true,"ip-restriction":true,"syslog":true,"mqtt-proxy":true}, context: init_worker_by_lua*","\n"]
```
## 启用插件
该插件默认为禁用状态,你可以在 `./conf/config.yaml` 中启用 `error-log-logger` 插件。你可以参考如下示例启用插件:
```yaml title="./conf/config.yaml"
plugins: # plugin list
......
- request-id
- hmac-auth
- api-breaker
- error-log-logger # enable plugin `error-log-logger
```
完成插件配置后,你需要重新加载 APISIX插件才会生效。
:::note 注意
该插件属于 APISIX 全局性插件,不需要在任何路由或服务中绑定。
:::
### 配置 TCP 服务器地址
你可以通过配置插件元数据来设置 TCP 服务器地址,如下所示:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"tcp": {
"host": "127.0.0.1",
"port": 1999
},
"inactive_timeout": 1
}'
```
### 配置 SkyWalking OAP 服务器地址
通过以下配置插件元数据设置 SkyWalking OAP 服务器地址,如下所示:
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"skywalking": {
"endpoint_addr": "http://127.0.0.1:12800/v3/logs"
},
"inactive_timeout": 1
}'
```
### 配置 ClickHouse 数据库
该插件支持将错误日志作为字符串发送到 ClickHouse 服务器中对应表的 `data` 字段。
你可以按照如下方式进行配置:
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"clickhouse": {
"user": "default",
"password": "a",
"database": "error_log",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:8123"
}
}'
```
### 配置 Kafka
该插件支持将错误日志发送到 Kafka你可以按照如下方式进行配置
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"kafka":{
"brokers":[
{
"host":"127.0.0.1",
"port":9092
}
],
"kafka_topic":"test2"
},
"level":"ERROR",
"inactive_timeout":1
}'
```
## 删除插件
当你不再需要该插件时,只需要在 `./conf/config.yaml` 中删除或注释该插件即可。
```yaml
plugins: # plugin list
... ...
- request-id
- hmac-auth
- api-breaker
#- error-log-logger # enable plugin `error-log-logger
```

View File

@@ -0,0 +1,33 @@
---
title: ext-plugin-post-req
keywords:
- Apache APISIX
- Plugin
- ext-plugin-post-req
description: 本文介绍了关于 Apache APISIX `ext-plugin-post-req` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`ext-plugin-post-req` 插件的功能与 `ext-plugin-pre-req` 插件的不同之处在于:`ext-plugin-post-req` 插件是在内置 Lua 插件执行之后且在请求到达上游之前工作。
你可以参考 [ext-plugin-pre-req](./ext-plugin-pre-req.md) 文档,学习如何配置和使用 `ext-plugin-post-req` 插件。

View File

@@ -0,0 +1,119 @@
---
title: ext-plugin-post-resp
keywords:
- Apache APISIX
- API 网关
- Plugin
- ext-plugin-post-resp
description: 本文介绍了关于 Apache APISIX `ext-plugin-post-resp` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`ext-plugin-post-resp` 插件用于在执行内置 Lua 插件之前和在 Plugin Runner 内运行特定的 External Plugin。
`ext-plugin-post-resp` 插件将在请求获取到上游的响应之后执行。
启用本插件之后APISIX 将使用 [lua-resty-http](https://github.com/api7/lua-resty-http) 库向上游发起请求,这会导致:
- [proxy-control](./proxy-control.md) 插件不可用
- [proxy-mirror](./proxy-mirror.md) 插件不可用
- [proxy-cache](./proxy-cache.md) 插件不可用
- [APISIX 与上游间的双向认证](../mtls.md#apisix-与上游间的双向认证) 功能尚不可用
如果你想了解更多关于 External Plugin 的信息,请参考 [External Plugin](../external-plugin.md)
:::note
External Plugin 执行的结果会影响当前请求的响应。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------ | ------ | ------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| conf | array | 否 | | [{"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"}] | 在 Plugin Runner 内执行的插件列表的配置。 |
| allow_degradation | boolean| 否 | false | [false, true] | 当 Plugin Runner 临时不可用时是否允许请求继续,当值设置为 `true` 时则自动允许请求继续。 |
## 启用插件
以下示例展示了如何在指定路由中启用 `ext-plugin-post-resp` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"ext-plugin-post-resp": {
"conf" : [
{"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl -i http://127.0.0.1:9080/index.html
```
在返回结果中可以看到刚刚配置的 Plugin Runner 已经被触发,同时 `ext-plugin-A` 插件也已经被执行。
## 删除插件
当你需要禁用 `ext-plugin-post-resp` 插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,110 @@
---
title: ext-plugin-pre-req
keywords:
- Apache APISIX
- API 网关
- Plugin
- ext-plugin-pre-req
description: 本文介绍了关于 Apache APISIX `ext-plugin-pre-req` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`ext-plugin-pre-req` 插件用于在执行内置 Lua 插件之前和在 Plugin Runner 内运行特定的 External Plugin。
如果你想了解更多关于 External Plugin 的信息,请参考 [External Plugin](../external-plugin.md)
:::note
External Plugin 执行的结果会影响当前请求的行为。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------ | ------ | ------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| conf | array | 否 | | [{"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"}] | 在 Plugin Runner 内执行的插件列表的配置。 |
| allow_degradation | boolean| 否 | false | [false, true] | 当 Plugin Runner 临时不可用时是否允许请求继续,当值设置为 true 时则自动允许请求继续。 |
## 启用插件
以下示例展示了如何在指定路由中启用 `ext-plugin-pre-req` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"ext-plugin-pre-req": {
"conf" : [
{"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl -i http://127.0.0.1:9080/index.html
```
在返回结果中可以看到刚刚配置的 Plugin Runner 已经被触发,同时 `ext-plugin-A` 插件也已经被执行。
## 删除插件
当你需要禁用 `ext-plugin-pre-req` 插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,299 @@
---
title: fault-injection
keywords:
- Apache APISIX
- API 网关
- Plugin
- Fault Injection
- fault-injection
description: 本文介绍了关于 Apache APISIX `fault-injection` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`fault-injection` 插件是故障注入插件,该插件可以和其他插件一起使用,并在其他插件执行前被执行。
## 属性
| 名称 | 类型 | 必选项 | 有效值 | 描述 |
| ----------------- | ------- | ---- | ---------- | -------------------------- |
| abort.http_status | integer | 是 | [200, ...] | 返回给客户端的 HTTP 状态码 |
| abort.body | string | 否 | | 返回给客户端的响应数据。支持使用 NGINX 变量,如 `client addr: $remote_addr\n`|
| abort.headers | object | 否 | | 返回给客户端的响应头,可以包含 NGINX 变量,如 `$remote_addr` |
| abort.percentage | integer | 否 | [0, 100] | 将被中断的请求占比 |
| abort.vars | array[] | 否 | | 执行故障注入的规则,当规则匹配通过后才会执行故障注。`vars` 是一个表达式的列表,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 |
| delay.duration | number | 是 | | 延迟时间,可以指定小数 |
| delay.percentage | integer | 否 | [0, 100] | 将被延迟的请求占比 |
| delay.vars | array[] | 否 | | 执行请求延迟的规则,当规则匹配通过后才会延迟请求。`vars` 是一个表达式列表,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 |
:::info IMPORTANT
`abort` 属性将直接返回给客户端指定的响应码并且终止其他插件的执行。
`delay` 属性将延迟某个请求,并且还会执行配置的其他插件。
`abort``delay` 属性至少要配置一个。
:::
:::tip
`vars` 是由 [`lua-resty-expr`](https://github.com/api7/lua-resty-expr) 的表达式组成的列表,它可以灵活的实现规则之间的 AND/OR 关系,示例如下::
```json
[
[
[ "arg_name","==","jack" ],
[ "arg_age","==",18 ]
],
[
[ "arg_name2","==","allen" ]
]
]
```
以上示例表示前两个表达式之间的关系是 AND而前两个和第三个表达式之间的关系是 OR。
:::
## 启用插件
你可以在指定路由启用 `fault-injection` 插件,并指定 `abort` 属性。如下所示:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"fault-injection": {
"abort": {
"http_status": 200,
"body": "Fault Injection!"
}
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
同样,我们也可以指定 `delay` 属性。如下所示:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"fault-injection": {
"delay": {
"duration": 3
}
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
还可以同时为指定路由启用 `fault-injection` 插件,并指定 `abort` 属性和 `delay` 属性的 `vars` 规则。如下所示:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"fault-injection": {
"abort": {
"http_status": 403,
"body": "Fault Injection!\n",
"vars": [
[
[ "arg_name","==","jack" ]
]
]
},
"delay": {
"duration": 2,
"vars": [
[
[ "http_age","==","18" ]
]
]
}
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
## 测试插件
通过上述示例启用插件后,可以向路由发起如下请求:
```shell
curl http://127.0.0.1:9080/hello -i
```
```shell
HTTP/1.1 200 OK
Date: Mon, 13 Jan 2020 13:50:04 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server
Fault Injection!
```
通过如下命令可以向配置 `delay` 属性的路由发起请求:
```shell
time curl http://127.0.0.1:9080/hello -i
```
```shell
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 6
Connection: keep-alive
Server: APISIX web server
Date: Tue, 14 Jan 2020 14:30:54 GMT
Last-Modified: Sat, 11 Jan 2020 12:46:21 GMT
hello
real 0m3.034s
user 0m0.007s
sys 0m0.010s
```
### 标准匹配的故障注入
你可以在 `fault-injection` 插件中使用 `vars` 规则设置特定规则:
```Shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"fault-injection": {
"abort": {
"http_status": 403,
"body": "Fault Injection!\n",
"vars": [
[
[ "arg_name","==","jack" ]
]
]
}
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
使用不同的 `name` 参数测试路由:
```Shell
curl "http://127.0.0.1:9080/hello?name=allen" -i
```
没有故障注入的情况下,你可以得到如下结果:
```shell
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
Date: Wed, 20 Jan 2021 07:21:57 GMT
Server: APISIX/2.2
hello
```
如果我们将 `name` 设置为与配置相匹配的名称,`fault-injection` 插件将被执行:
```Shell
curl "http://127.0.0.1:9080/hello?name=jack" -i
```
```shell
HTTP/1.1 403 Forbidden
Date: Wed, 20 Jan 2021 07:23:37 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.2
Fault Injection!
```
## 删除插件
当你需要禁用 `fault-injection` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,242 @@
---
title: file-logger
keywords:
- APISIX
- API 网关
- Plugin
- file-logger
description: API 网关 Apache APISIX file-logger 插件可用于将日志数据存储到指定位置。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`file-logger` 插件可用于将日志数据存储到指定位置。
:::tip 提示
`file-logger` 插件特点如下:
- 可将指定路由的日志发送到指定位置,方便你在本地统计各个路由的请求和响应数据。在使用 [debug mode](../../../en/latest/debug-mode.md) 时,你可以很轻松地将出现问题的路由的日志输出到指定文件中,从而更方便地排查问题。
- 可以获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html),而 `access.log` 仅能使用 NGINX 变量。
- 支持热加载,你可以在路由中随时更改其配置并立即生效。而修改 `access.log` 相关配置,则需要重新加载 APISIX。
- 支持以 JSON 格式保存日志数据。
- 可以在 `log phase` 阶段修改 `file-logger` 执行的函数来收集你所需要的信息。
:::
## 属性
| 名称 | 类型 | 必选项 | 描述 |
| ---------------- | ------- |-----| ------------------------------------------------ |
| path | string | 是 | 自定义输出文件路径。例如:`logs/file.log`。 |
| log_format | object | 否 | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | 当设置为 `true` 时,日志中将包含请求体。如果请求体太大而无法在内存中保存,则由于 Nginx 的限制,无法记录请求体。|
| include_req_body_expr | array | 否 | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | 当设置为 `true` 时,生成的文件包含响应体。 |
| include_resp_body_expr | array | 否 | 当 `include_resp_body` 属性设置为 `true` 时,使用该属性并基于 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 进行过滤。如果存在,则仅在表达式计算结果为 `true` 时记录响应。 |
| match | array[array] | 否 | 当设置了这个选项后,只有匹配规则的日志才会被记录。`match` 是一个表达式列表,具体请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 |
### 默认日志格式示例
```json
{
"service_id": "",
"apisix_latency": 100.99999809265,
"start_time": 1703907485819,
"latency": 101.99999809265,
"upstream_latency": 1,
"client_ip": "127.0.0.1",
"route_id": "1",
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"request": {
"headers": {
"host": "127.0.0.1:1984",
"content-type": "application/x-www-form-urlencoded",
"user-agent": "lua-resty-http/0.16.1 (Lua) ngx_lua/10025",
"content-length": "12"
},
"method": "POST",
"size": 194,
"url": "http://127.0.0.1:1984/hello?log_body=no",
"uri": "/hello?log_body=no",
"querystring": {
"log_body": "no"
}
},
"response": {
"headers": {
"content-type": "text/plain",
"connection": "close",
"content-length": "12",
"server": "APISIX/3.7.0"
},
"status": 200,
"size": 123
},
"upstream": "127.0.0.1:1982"
}
```
## 插件元数据设置
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 可选 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../../../en/latest/apisix-variable.md) 或 [NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::note 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `file-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/file-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你可以在日志系统中看到如下类似日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"file-logger": {
"path": "logs/file.log"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
访问成功后,你可以在对应的 `logs` 目录下找到 `file.log` 文件。
## 过滤日志
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"file-logger": {
"path": "logs/file.log",
"match": [
[
[ "arg_name","==","jack" ]
]
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
},
"uri": "/hello"
}'
```
测试:
```shell
curl -i http://127.0.0.1:9080/hello?name=jack
```
在 `logs/file.log` 中可以看到日志记录
```shell
curl -i http://127.0.0.1:9080/hello?name=rose
```
在 `logs/file.log` 中看不到日志记录
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
}
}'
```

View File

@@ -0,0 +1,189 @@
---
title: forward-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- Forward Authentication
- forward-auth
description: 本文介绍了关于 Apache APISIX `forward-auth` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`forward-auth` 插件使用的是经典外部认证。当身份认证失败时,可以实现自定义错误或者重定向到认证页面的场景。
`forward-auth` 插件巧妙地将身份认证和授权逻辑移到了一个专门的外部服务中APISIX 将用户的请求转发给认证服务并阻塞原始请求,然后在认证服务下以非 2xx 状态响应时进行结果替换。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------------- | ------| ------- | -------------- | -------------------------------------------------------------------------------------------------------------------- |
| uri | string | 是 | | | 设置 `authorization` 服务的地址 (例如https://localhost:9188)。 |
| ssl_verify | boolean | 否 | true | [true, false] | 当设置为 `true` 时,验证 SSL 证书。 |
| request_method | string | 否 | GET | ["GET","POST"] | 客户端向 `authorization` 服务发送请求的方法。当设置为 POST 时,会将 `request body` 转发至 `authorization` 服务。 |
| request_headers | array[string] | 否 | | | 设置需要由客户端转发到 `authorization` 服务的请求头。如果没有设置,则只发送 APISIX 提供的 headers (例如X-Forwarded-XXX)。 |
| upstream_headers | array[string] | 否 | | | 认证通过时,设置 `authorization` 服务转发至 `upstream` 的请求头。如果不设置则不转发任何请求头。 |
| client_headers | array[string] | 否 | | | 认证失败时,由 `authorization` 服务向 `client` 发送的响应头。如果不设置则不转发任何响应头。 |
| timeout | integer | 否 | 3000ms | [1, 60000]ms | `authorization` 服务请求超时时间。 |
| keepalive | boolean | 否 | true | [true, false] | HTTP 长连接。 |
| keepalive_timeout | integer | 否 | 60000ms | [1000, ...]ms | 长连接超时时间。 |
| keepalive_pool | integer | 否 | 5 | [1, ...]ms | 长连接池大小。 |
| allow_degradation | boolean | 否 | false | | 当设置为 `true` 时,允许在身份验证服务器不可用时跳过身份验证。 |
| status_on_error | integer | 否 | 403 | [200,...,599] | 设置授权服务出现网络错误时返回给客户端的 HTTP 状态。默认状态为“403”。 |
## 数据定义
APISIX 将生成并发送如下所示的请求头到认证服务:
| Scheme | HTTP Method | Host | URI | Source IP |
| ----------------- | ------------------ | ----------------- | --------------- | --------------- |
| X-Forwarded-Proto | X-Forwarded-Method | X-Forwarded-Host | X-Forwarded-Uri | X-Forwarded-For |
## 使用示例
首先,你需要设置一个外部认证服务。以下示例使用的是 Apache APISIX 无服务器插件模拟服务:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/auth' \
-H "X-API-KEY: $admin_key" \
-H 'Content-Type: application/json' \
-d '{
"uri": "/auth",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function (conf, ctx)
local core = require(\"apisix.core\");
local authorization = core.request.header(ctx, \"Authorization\");
if authorization == \"123\" then
core.response.exit(200);
elseif authorization == \"321\" then
core.response.set_header(\"X-User-ID\", \"i-am-user\");
core.response.exit(200);
else core.response.set_header(\"Location\", \"http://example.com/auth\");
core.response.exit(403);
end
end"
]
}
}
}'
```
现在你可以在指定 Route 上启用 `forward-auth` 插件:
```shell
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/1' \
-H "X-API-KEY: $admin_key" \
-d '{
"uri": "/headers",
"plugins": {
"forward-auth": {
"uri": "http://127.0.0.1:9080/auth",
"request_headers": ["Authorization"],
"upstream_headers": ["X-User-ID"],
"client_headers": ["Location"]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
完成上述配置后,可通过以下三种方式进行测试:
- 在请求头中发送认证的详细信息:
```shell
curl http://127.0.0.1:9080/headers -H 'Authorization: 123'
```
```
{
"headers": {
"Authorization": "123",
"Next": "More-headers"
}
}
```
- 转发认证服务响应头到 Upstream。
```shell
curl http://127.0.0.1:9080/headers -H 'Authorization: 321'
```
```
{
"headers": {
"Authorization": "321",
"X-User-ID": "i-am-user",
"Next": "More-headers"
}
}
```
- 当授权失败时,认证服务可以向用户发送自定义响应:
```shell
curl -i http://127.0.0.1:9080/headers
```
```shell
HTTP/1.1 403 Forbidden
Location: http://example.com/auth
```
## 删除插件
当你需要禁用 `forward-auth` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```

View File

@@ -0,0 +1,191 @@
---
title: GM
keywords:
- Apache APISIX
- Plugin
- GM
description: 本文介绍了关于 Apache APISIX gm 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`gm` 插件能启用国密相关的功能。目前支持通过该插件动态配置国密双证书。
:::note 相关介绍
国密就是国产化的密码算法。在我们日常开发过程中会接触到各种各样的密码算法,如 RSA、SHA256 等等。为了达到更高的安全等级,许多大公司和国家会制定自己的密码算法。国密就是这样一组由中国国家密码管理局制定的密码算法。在国际形势越发复杂多变的今天,密码算法的国产化替代,在一些领域已经成为了一股势不可挡的潮流。
:::
## 启用插件
**该插件要求 Apache APISIX 运行在编译了 Tongsuo 的 APISIX-Runtime 上。**
首先,我们需要安装 Tongsuo此处我们选择编译出 Tongsuo 的动态链接库):
```
# TODO: use a fixed release once they have created one.
# See https://github.com/Tongsuo-Project/Tongsuo/issues/318
git clone https://github.com/api7/tongsuo --depth 1
pushd tongsuo
./config shared enable-ntls -g --prefix=/usr/local/tongsuo
make -j2
sudo make install_sw
```
其次,我们需要构建 APISIX-Runtime让它使用 Tongsuo 作为 SSL 库:
```
export OR_PREFIX=/usr/local/openresty
export openssl_prefix=/usr/local/tongsuo
export zlib_prefix=$OR_PREFIX/zlib
export pcre_prefix=$OR_PREFIX/pcre
export cc_opt="-DNGX_LUA_ABORT_AT_PANIC -I${zlib_prefix}/include -I${pcre_prefix}/include -I${openssl_prefix}/include"
export ld_opt="-L${zlib_prefix}/lib -L${pcre_prefix}/lib -L${openssl_prefix}/lib64 -Wl,-rpath,${zlib_prefix}/lib:${pcre_prefix}/lib:${openssl_prefix}/lib64"
./build-apisix-runtime.sh
```
该插件默认是禁用状态,你需要将其添加到配置文件(`./conf/config.yaml`)中才可以启用它:
```yaml
plugins:
- ...
- gm
```
由于 APISIX 的默认 cipher 中不包含国密 cipher所以我们还需要在配置文件`./conf/config.yaml`)中设置 cipher
```yaml
apisix:
...
ssl:
...
# 可按实际情况调整。错误的 cipher 会导致“no shared cipher”或“no ciphers available”报错。
ssl_ciphers: HIGH:!aNULL:!MD5
```
配置完成后,重新加载 APISIX此时 APISIX 将会启用国密相关的逻辑。
## 测试插件
在测试插件之前我们需要准备好国密双证书。Tongsuo 提供了生成[SM2 双证书](https://www.yuque.com/tsdoc/ts/sulazb)的教程。
在下面的例子中,我们将用到如下的证书:
```
# 客户端加密证书和密钥
t/certs/client_enc.crt
t/certs/client_enc.key
# 客户端签名证书和密钥
t/certs/client_sign.crt
t/certs/client_sign.key
# CA 和中间 CA 打包在一起的文件,用于设置受信任的 CA
t/certs/gm_ca.crt
# 服务端加密证书和密钥
t/certs/server_enc.crt
t/certs/server_enc.key
# 服务端签名证书和密钥
t/certs/server_sign.crt
t/certs/server_sign.key
```
此外,我们还需要准备 Tongsuo 命令行工具。
```
./config enable-ntls -static
make -j2
# 生成的命令行工具在 apps 目录下
mv apps/openssl ..
```
你也可以采用非静态编译的方式,不过就需要根据具体环境,自己解决动态链接库的路径问题了。
以下示例展示了如何在指定域名中启用 `gm` 插件:
创建对应的 SSL 对象:
```python
#!/usr/bin/env python
# coding: utf-8
import sys
# sudo pip install requests
import requests
if len(sys.argv) <= 3:
print("bad argument")
sys.exit(1)
with open(sys.argv[1]) as f:
enc_cert = f.read()
with open(sys.argv[2]) as f:
enc_key = f.read()
with open(sys.argv[3]) as f:
sign_cert = f.read()
with open(sys.argv[4]) as f:
sign_key = f.read()
api_key = "edd1c9f034335f136f87ad84b625c8f1"
resp = requests.put("http://127.0.0.1:9180/apisix/admin/ssls/1", json={
"cert": enc_cert,
"key": enc_key,
"certs": [sign_cert],
"keys": [sign_key],
"gm": True,
"snis": ["localhost"],
}, headers={
"X-API-KEY": api_key,
})
print(resp.status_code)
print(resp.text)
```
将上面的脚本保存为 `./create_gm_ssl.py`,运行:
```shell
./create_gm_ssl.py t/certs/server_enc.crt t/certs/server_enc.key t/certs/server_sign.crt t/certs/server_sign.key
```
输出结果如下所示:
```
200
{"key":"\/apisix\/ssls\/1","value":{"keys":["Yn...
```
完成上述准备后,可以使用如下命令测试插件是否启用成功:
```shell
./openssl s_client -connect localhost:9443 -servername localhost -cipher ECDHE-SM2-WITH-SM4-SM3 -enable_ntls -ntls -verifyCAfile t/certs/gm_ca.crt -sign_cert t/certs/client_sign.crt -sign_key t/certs/client_sign.key -enc_cert t/certs/client_enc.crt -enc_key t/certs/client_enc.key
```
这里 `./openssl` 是前面得到的 Tongsuo 命令行工具。9443 是 APISIX 默认的 HTTPS 端口。
如果一切正常,可以看到连接建立了起来,并输出如下信息:
```
...
New, NTLSv1.1, Cipher is ECDHE-SM2-SM4-CBC-SM3
...
```
## 删除插件
如果不再使用此插件,可将 `gm` 插件从 `./conf/config.yaml` 配置文件中移除,然后重启 APISIX 或者通过插件热加载的接口触发插件的卸载。

View File

@@ -0,0 +1,231 @@
---
title: google-cloud-logging
keywords:
- APISIX
- API 网关
- 插件
- Google Cloud logging
- 日志
description: API 网关 Apache APISIX 的 google-cloud-logging 插件可用于将请求日志转发到 Google Cloud Logging Service 中进行分析和存储。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`google-cloud-logging` 插件可用于将请求日志发送到 [Google Cloud Logging Service](https://cloud.google.com/logging/) 进行分析和存储。
## 属性
| 名称 | 必选项 | 默认值 | 描述 |
| ----------------------- | -------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| auth_config | 是 | | `auth_config``auth_file` 必须配置一个。 |
| auth_config.client_email | 是 | | 谷歌服务帐号的 email 参数。 |
| auth_config.private_key | 是 | | 谷歌服务帐号的私钥参数。 |
| auth_config.project_id | 是 | | 谷歌服务帐号的项目 ID。 |
| auth_config.token_uri | 是 | https://oauth2.googleapis.com/token | 请求谷歌服务帐户的令牌的 URI。 |
| auth_config.entries_uri | 否 | https://logging.googleapis.com/v2/entries:write | 谷歌日志服务写入日志条目的 API。 |
| auth_config.scope | 否 | | 谷歌服务账号的访问范围,可参考 [OAuth 2.0 Scopes for Google APIs](https://developers.google.com/identity/protocols/oauth2/scopes#logging)。可选项:"https://www.googleapis.com/auth/logging.read"、"https://www.googleapis.com/auth/logging.write"、"https://www.googleapis.com/auth/logging.admin"、"https://www.googleapis.com/auth/cloud-platform"。|
| auth_config.scopes | 废弃 | | 谷歌服务账号的访问范围,推荐使用 `auth_config.scope` |
| auth_file | 是 | | `auth_config``auth_file` 必须配置一个。 |
| ssl_verify | 否 | true | 当设置为 `true` 时,启用 `SSL` 验证。 |
| resource | 否 | {"type": "global"} | 谷歌监控资源,请参考 [MonitoredResource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource)。 |
| log_id | 否 | apisix.apache.org%2Flogs | 谷歌日志 ID请参考 [LogEntry](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)。 |
| log_format | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
注意schema 中还定义了 `encrypt_fields = {"auth_config.private_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
该插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免该插件频繁地提交数据。默认情况下每 `5` 秒钟或队列中的数据达到 `1000` 条时,批处理器会自动提交数据,如需了解更多信息或自定义配置,请参考 [Batch Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"insertId": "0013a6afc9c281ce2e7f413c01892bdc",
"labels": {
"source": "apache-apisix-google-cloud-logging"
},
"logName": "projects/apisix/logs/apisix.apache.org%2Flogs",
"httpRequest": {
"requestMethod": "GET",
"requestUrl": "http://localhost:1984/hello",
"requestSize": 59,
"responseSize": 118,
"status": 200,
"remoteIp": "127.0.0.1",
"serverIp": "127.0.0.1:1980",
"latency": "0.103s"
},
"resource": {
"type": "global"
},
"jsonPayload": {
"service_id": "",
"route_id": "1"
},
"timestamp": "2024-01-06T03:34:45.065Z"
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `google-cloud-logging` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/google-cloud-logging \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```json
{"partialSuccess":false,"entries":[{"jsonPayload":{"client_ip":"127.0.0.1","host":"localhost","@timestamp":"2023-01-09T14:47:25+08:00","route_id":"1"},"resource":{"type":"global"},"insertId":"942e81f60b9157f0d46bc9f5a8f0cc40","logName":"projects/apisix/logs/apisix.apache.org%2Flogs","timestamp":"2023-01-09T14:47:25+08:00","labels":{"source":"apache-apisix-google-cloud-logging"}}]}
```
## 启用插件
以下示例展示了如何在指定路由上启用该插件:
**完整配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"google-cloud-logging": {
"auth_config":{
"project_id":"apisix",
"client_email":"your service account email@apisix.iam.gserviceaccount.com",
"private_key":"-----BEGIN RSA PRIVATE KEY-----your private key-----END RSA PRIVATE KEY-----",
"token_uri":"https://oauth2.googleapis.com/token",
"scope":[
"https://www.googleapis.com/auth/logging.admin"
],
"entries_uri":"https://logging.googleapis.com/v2/entries:write"
},
"resource":{
"type":"global"
},
"log_id":"apisix.apache.org%2Flogs",
"inactive_timeout":10,
"max_retry_count":0,
"max_retry_count":0,
"buffer_duration":60,
"retry_delay":1,
"batch_max_size":1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
**最小化配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"google-cloud-logging": {
"auth_config":{
"project_id":"apisix",
"client_email":"your service account email@apisix.iam.gserviceaccount.com",
"private_key":"-----BEGIN RSA PRIVATE KEY-----your private key-----END RSA PRIVATE KEY-----"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
访问成功后,你可以登录 [Google Cloud Logging Service](https://console.cloud.google.com/logs/viewer) 查看相关日志。
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,396 @@
---
title: grpc-transcode
keywords:
- Apache APISIX
- API 网关
- Plugin
- gRPC Web
- grpc-web
description: 本文介绍了关于 Apache APISIX `grpc-transcode` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
使用 `grpc-transcode` 插件可以在 HTTP 和 gRPC 请求之间进行转换。
APISIX 接收 HTTP 请求后,首先对请求进行转码,并将转码后的请求转发到 gRPC 服务,获取响应并以 HTTP 格式将其返回给客户端。
<!-- TODO: use an image here to explain the concept better -->
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| --------- | ------------------------------------------------- | ----- | ------ ------------------------------ |
| proto_id | string/integer | 是 | | `.proto` 内容的 id。 |
| service | string | 是 | | gRPC 服务名。 |
| method | string | 是 | | gRPC 服务中要调用的方法名。 |
| deadline | number | 否 | 0 | gRPC 服务的 deadline单位为ms。 |
| pb_option | array[string([pb_option_def](#pb_option-的选项))] | 否 | | proto 编码过程中的转换选项。 |
| show_status_in_body | boolean | 否 | false | 是否在返回体中展示解析过的 `grpc-status-details-bin` |
| status_detail_type | string | 否 | | `grpc-status-details-bin` 中 [details](https://github.com/googleapis/googleapis/blob/b7cb84f5d42e6dba0fdcc2d8689313f6a8c9d7b9/google/rpc/status.proto#L46) 部分对应的 message type如果不指定此部分不进行解码 |
### pb_option 的选项
| 类型 | 有效值 |
|-----------------|-------------------------------------------------------------------------------------------|
| enum as result | `enum_as_name`, `enum_as_value` |
| int64 as result | `int64_as_number`, `int64_as_string`, `int64_as_hexstring` |
| default values | `auto_default_values`, `no_default_values`, `use_default_values`, `use_default_metatable` |
| hooks | `enable_hooks`, `disable_hooks` |
## 启用插件
在启用插件之前,你必须将 `.proto``.pb` 文件的内容添加到 APISIX。
可以使用 `/admin/protos/id` 接口将文件的内容添加到 `content` 字段:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/protos/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}"
}'
```
如果你的 `.proto` 文件包含 `import`,或者想要把多个 `.proto` 文件合并成一个 proto你可以生成一个 `.pb` 文件并在 APISIX 中使用它。
假设已经有一个 `.proto` 文件(`proto/helloworld.proto`),它导入了另一个 `proto` 文件:
```proto
syntax = "proto3";
package helloworld;
import "proto/import.proto";
...
```
首先,让我们从 `.proto` 文件创建一个 `.pb` 文件。
```shell
protoc --include_imports --descriptor_set_out=proto.pb proto/helloworld.proto
```
输出的二进制文件 `proto.pb` 将同时包含 `helloworld.proto``import.proto`
然后将 `proto.pb` 的内容作为 proto 的 `content` 字段提交。
由于 proto 的内容是二进制的,我们需要使用以下 shell 命令将其转换成 `base64`
```shell
curl http://127.0.0.1:9180/apisix/admin/protos/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"content" : "'"$(base64 -w0 /path/to/proto.pb)"'"
}'
```
返回 `HTTP/1.1 201 Created` 结果如下:
```
{"node":{"value":{"create_time":1643879753,"update_time":1643883085,"content":"CmgKEnByb3RvL2ltcG9ydC5wcm90bxIDcGtnIhoKBFVzZXISEgoEbmFtZRgBIAEoCVIEbmFtZSIeCghSZXNwb25zZRISCgRib2R5GAEgASgJUgRib2R5QglaBy4vcHJvdG9iBnByb3RvMwq9AQoPcHJvdG8vc3JjLnByb3RvEgpoZWxsb3dvcmxkGhJwcm90by9pbXBvcnQucHJvdG8iPAoHUmVxdWVzdBIdCgR1c2VyGAEgASgLMgkucGtnLlVzZXJSBHVzZXISEgoEYm9keRgCIAEoCVIEYm9keTI5CgpUZXN0SW1wb3J0EisKA1J1bhITLmhlbGxvd29ybGQuUmVxdWVzdBoNLnBrZy5SZXNwb25zZSIAQglaBy4vcHJvdG9iBnByb3RvMw=="},"key":"\/apisix\/proto\/1"}}
```
现在我们可以在指定路由中启用 `grpc-transcode` 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/grpctest",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "helloworld.Greeter",
"method": "SayHello"
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'
```
:::note
此处使用的 Upstream 应该是 gRPC 服务。请注意,`scheme` 需要设置为 `grpc`
可以使用 [grpc_server_example](https://github.com/api7/grpc_server_example) 进行测试。
:::
## 测试插件
通过上述示例配置插件后,你可以向 APISIX 发出请求以从 gRPC 服务(通过 APISIX获得响应
访问上面配置的 route
```shell
curl -i http://127.0.0.1:9080/grpctest?name=world
```
返回结果
```Shell
HTTP/1.1 200 OK
Date: Fri, 16 Aug 2019 11:55:36 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server
Proxy-Connection: keep-alive
{"message":"Hello world"}
```
你也可以配置 `pb_option`,如下所示:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/23 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/zeebe/WorkflowInstanceCreate",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "gateway_protocol.Gateway",
"method": "CreateWorkflowInstance",
"pb_option":["int64_as_string"]
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:26500": 1
}
}
}'
```
可以通过如下命令检查刚刚配置的路由:
```shell
curl -i "http://127.0.0.1:9080/zeebe/WorkflowInstanceCreate?bpmnProcessId=order-process&version=1&variables=\{\"orderId\":\"7\",\"ordervalue\":99\}"
```
```Shell
HTTP/1.1 200 OK
Date: Wed, 13 Nov 2019 03:38:27 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
grpc-encoding: identity
grpc-accept-encoding: gzip
Server: APISIX web server
Trailer: grpc-status
Trailer: grpc-message
{"workflowKey":"#2251799813685260","workflowInstanceKey":"#2251799813688013","bpmnProcessId":"order-process","version":1}
```
## 在返回体中展示 `grpc-status-details-bin`
如果 gRPC 服务返回了错误,返回头中可能存在 `grpc-status-details-bin` 字段对错误进行描述,你可以解码该字段,并展示在返回体中。
上传 proto 文件:
```shell
curl http://127.0.0.1:9180/apisix/admin/protos/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc GetErrResp (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
repeated string items = 2;
}
message HelloReply {
string message = 1;
repeated string items = 2;
}"
}'
```
启用 `grpc-transcode` 插件,并设置选项 `show_status_in_body``true`
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/grpctest",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "helloworld.Greeter",
"method": "GetErrResp",
"show_status_in_body": true
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'
```
访问上面配置的 route
```shell
curl -i http://127.0.0.1:9080/grpctest?name=world
```
返回结果
```Shell
HTTP/1.1 503 Service Temporarily Unavailable
Date: Wed, 10 Aug 2022 08:59:46 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
grpc-status: 14
grpc-message: Out of service
grpc-status-details-bin: CA4SDk91dCBvZiBzZXJ2aWNlGlcKKnR5cGUuZ29vZ2xlYXBpcy5jb20vaGVsbG93b3JsZC5FcnJvckRldGFpbBIpCAESHFRoZSBzZXJ2ZXIgaXMgb3V0IG9mIHNlcnZpY2UaB3NlcnZpY2U
Server: APISIX web server
{"error":{"details":[{"type_url":"type.googleapis.com\/helloworld.ErrorDetail","value":"\b\u0001\u0012\u001cThe server is out of service\u001a\u0007service"}],"message":"Out of service","code":14}}
```
注意返回体中还存在未解码的字段,如果需要解码该字段,需要在上传的 proto 文件中加上该字段对应的 `message type`
```shell
curl http://127.0.0.1:9180/apisix/admin/protos/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc GetErrResp (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
repeated string items = 2;
}
message HelloReply {
string message = 1;
repeated string items = 2;
}
message ErrorDetail {
int64 code = 1;
string message = 2;
string type = 3;
}"
}'
```
同时配置选项 `status_detail_type``helloworld.ErrorDetail`
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/grpctest",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "helloworld.Greeter",
"method": "GetErrResp",
"show_status_in_body": true,
"status_detail_type": "helloworld.ErrorDetail"
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'
```
此时就能返回完全解码后的结果
```Shell
HTTP/1.1 503 Service Temporarily Unavailable
Date: Wed, 10 Aug 2022 09:02:46 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
grpc-status: 14
grpc-message: Out of service
grpc-status-details-bin: CA4SDk91dCBvZiBzZXJ2aWNlGlcKKnR5cGUuZ29vZ2xlYXBpcy5jb20vaGVsbG93b3JsZC5FcnJvckRldGFpbBIpCAESHFRoZSBzZXJ2ZXIgaXMgb3V0IG9mIHNlcnZpY2UaB3NlcnZpY2U
Server: APISIX web server
{"error":{"details":[{"type":"service","message":"The server is out of service","code":1}],"message":"Out of service","code":14}}
```
## 删除插件
当你需要禁用 `grpc-transcode` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/111 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/grpctest",
"plugins": {},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'
```

View File

@@ -0,0 +1,113 @@
---
title: grpc-web
keywords:
- Apache APISIX
- API 网关
- Plugin
- gRPC Web
- grpc-web
description: 本文介绍了关于 Apache APISIX `grpc-web` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`grpc-web` 插件是一个代理插件,可以处理从 JavaScript 客户端到 gRPC Service 的 [gRPC Web](https://github.com/grpc/grpc-web) 请求。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|---------------------| ------- |----|-----------------------------------------|----------------------------------------------------------------|
| cors_allow_headers | string | 否 | "content-type,x-grpc-web,x-user-agent" | 允许跨域访问时请求方携带哪些非 `CORS 规范` 以外的 Header。如果你有多个 Header请使用 `,` 分割。 |
## 启用插件
你可以通过如下命令在指定路由上启用 `gRPC-web` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri":"/grpc/web/*",
"plugins":{
"grpc-web":{}
},
"upstream":{
"scheme":"grpc",
"type":"roundrobin",
"nodes":{
"127.0.0.1:1980":1
}
}
}'
```
:::info IMPORTANT
在使用 `gRPC Web` 代理插件时,路由必须使用**前缀匹配**模式(例如:`/*``/grpc/example/*`),因为 `gRPC Web` 客户端会在 URI 中传递 `proto` 中声明的**包名称**、**服务接口名称**、**方法名称**等信息(例如:`/path/a6.RouteService/Insert`)。
因此,在使用**绝对匹配**时将无法命中插件和提取 `proto` 信息。
:::
## 测试插件
请参考 [gRPC-Web Client Runtime Library](https://www.npmjs.com/package/grpc-web)[Apache APISIX gRPC Web Test Framework](https://github.com/apache/apisix/tree/master/t/plugin/grpc-web) 了解如何配置你的 Web 客户端。
运行 gRPC Web 客户端后,你可以从浏览器或通过 Node.js 向 APISIX 发出请求。
:::note
请求方式仅支持 `POST``OPTIONS`,详细信息请参考:[CORS support](https://github.com/grpc/grpc-web/blob/master/doc/browser-features.md#cors-support)
内容类型支持 `application/grpc-web``application/grpc-web-text``application/grpc-web+proto``application/grpc-web-text+proto`,详细信息请参考:[Protocol differences vs gRPC over HTTP2](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2)
:::
## 删除插件
当你需要禁用 `grpc-web` 插件时,可以通过如下命令删除相应的 `JSON` 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri":"/grpc/web/*",
"plugins":{},
"upstream":{
"scheme":"grpc",
"type":"roundrobin",
"nodes":{
"127.0.0.1:1980":1
}
}
}'
```

View File

@@ -0,0 +1,126 @@
---
title: gzip
keywords:
- Apache APISIX
- API 网关
- Plugin
- gzip
description: 本文介绍了关于 Apache APISIX `gzip` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`gzip` 插件能动态设置 [NGINX](https://docs.nginx.com/nginx/admin-guide/web-server/compression/) 的压缩行为。
当启用 `gzip` 插件时,客户端在发起请求时需要在请求头中添加 `Accept-Encoding: gzip`,以表明客户端支持 `gzip` 压缩。APISIX 在接收到请求后,会根据客户端的支持情况和服务器配置动态判断是否对响应内容进行 gzip 压缩。如果判定条件得到满足APISIX 将在响应头中添加 `Content-Encoding: gzip` 字段,以指示响应内容已经通过 `gzip` 压缩。在客户端接收到响应后,根据响应头中的 `Content-Encoding` 字段使用相应的解压缩算法对响应内容进行解压,从而获取原始的响应内容。
:::info IMPORTANT
该插件要求 Apache APISIX 运行在 [APISIX-Runtime](../FAQ.md#如何构建-apisix-runtime-环境) 上。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------| -------------------- | ------- | -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| types | array[string] or "*" | 否 | ["text/html"] | | 动态设置 [`gzip_types`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_types) 指令,特殊值 `"*"` 匹配任何 MIME 类型。 |
| min_length | integer | 否 | 20 | >= 1 | 动态设置 [`gzip_min_length`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_min_length) 指令。 |
| comp_level | integer | 否 | 1 | [1, 9] | 动态设置 [`gzip_comp_level`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level) 指令。 |
| http_version | number | 否 | 1.1 | 1.1, 1.0 | 动态设置 [`gzip_http_version`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_http_version) 指令。 |
| buffers.number | integer | 否 | 32 | >= 1 | 动态设置 [`gzip_buffers`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_buffers) 指令 参数 `number`。 |
| buffers.size | integer | 否 | 4096 | >= 1 | 动态设置 [`gzip_buffers`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_buffers) 指令参数 `size`。单位为字节。 |
| vary | boolean | 否 | false | | 动态设置 [`gzip_vary`](https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_vary) 指令。 |
## 启用插件
以下示例展示了如何在指定路由中启用 `gzip` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"gzip": {
"buffers": {
"number": 8
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl http://127.0.0.1:9080/index.html -i -H "Accept-Encoding: gzip"
```
```
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Wed, 21 Jul 2021 03:52:55 GMT
Server: APISIX/2.7
Content-Encoding: gzip
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
```
## 删除插件
当你需要禁用 `gzip` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,760 @@
---
title: hmac-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- HMAC Authentication
- hmac-auth
description: hmac-auth 插件支持 HMAC 认证,保证请求的完整性,防止传输过程中的修改,增强 API 的安全性。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`hmac-auth` 插件支持 HMAC基于哈希的消息认证码认证作为一种确保请求完整性的机制防止它们在传输过程中被修改。要使用该插件您需要在 [Consumers](../terminology/consumer.md) 上配置 HMAC 密钥,并在 Routes 或 Services 上启用该插件。
当消费者成功通过身份验证后APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username``X-Credential-Indentifier` 和其他消费者自定义标头(如果已配置)。上游服务将能够区分消费者并根据需要实现其他逻辑。如果这些值中的任何一个不可用,则不会添加相应的标头。
启用后,插件会验证请求的 `Authorization` 标头中的 HMAC 签名,并检查传入的请求是否来自受信任的来源。具体来说,当 APISIX 收到 HMAC 签名的请求时,会从 `Authorization` 标头中提取密钥 ID。然后APISIX 会检索相应的消费者配置,包括密钥。如果密钥 ID 有效且存在APISIX 将使用请求的 `Date` 标头和密钥生成 HMAC 签名。如果生成的签名与 `Authorization` 标头中提供的签名匹配,则请求通过身份验证并转发到上游服务。
插件实现基于 [draft-cavage-http-signatures](https://www.ietf.org/archive/id/draft-cavage-http-signatures-12.txt)
## 属性
以下属性可用于 Consumers 或 Credentials 的配置。
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------------- | ------ | ------------- | ------------------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| access_key | string | 是 | | | 消费者的唯一标识符,用于标识相关配置,例如密钥。 |
| secret_key | string | 是 | | | 用于生成 HMAC 的密钥。此字段支持使用 [APISIX Secret](../terminology/secret.md) 资源将值保存在 Secret Manager 中。 |
以下属性可用于 Routes 或 Services 的配置。
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------------- | ------ | ------------- | ------------------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| allowed_algorithms | array[string] | 否 | ["hmac-sha1", "hmac-sha256", "hmac-sha512"] | "hmac-sha1"、"hmac-sha256" 和 "hmac-sha512" 的组合 | 允许的 HMAC 算法列表。 |
| clock_skew | integer | 否 | 300 | >=1 | 客户端请求的时间戳与 APISIX 服务器当前时间之间允许的最大时间差(以秒为单位)。这有助于解决客户端和服务器之间的时间同步差异,并防止重放攻击。时间戳将根据 Date 头中的时间(必须为 GMT 格式)进行计算。 |
| signed_headers | array[string] | 否 | | | 客户端请求的 HMAC 签名中应包含的 HMAC 签名头列表。 |
| validate_request_body | boolean | 否 | false | | 如果为 true则验证请求正文的完整性以确保在传输过程中没有被篡改。具体来说插件会创建一个 SHA-256 的 base64 编码 digest并将其与 `Digest` 头进行比较。如果 `Digest` 头丢失或 digest 不匹配,验证将失败。 |
| hide_credentials | boolean | 否 | false | | 如果为 true则不会将授权请求头传递给上游服务。 |
| anonymous_consumer | string | 否 | | | 匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。 |
注意schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
## 示例
下面的示例说明了如何在不同场景中使用“hmac-auth”插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 在路由上实现 HMAC 身份验证
以下示例演示如何在路由上实现 HMAC 身份验证。您还将在 `Consumer-Custom-Id` 标头中将消费者自定义 ID 附加到经过身份验证的请求,该 ID 可用于根据需要实现其他逻辑。
创建一个带有自定义 ID 标签的消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john",
"labels": {
"custom_id": "495aec6a"
}
}'
```
为消费者创建 `hmac-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-hmac-auth",
"plugins": {
"hmac-auth": {
"key_id": "john-key",
"secret_key": "john-secret-key"
}
}
}'
```
使用 `hmac-auth` 插件的默认配置创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "hmac-auth-route",
"uri": "/get",
"methods": ["GET"],
"plugins": {
"hmac-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
生成签名。您可以使用以下 Python 代码片段或其他技术栈:
```python title="hmac-sig-header-gen.py"
import hmac
import hashlib
import base64
from datetime import datetime, timezone
key_id = "john-key" # key id
secret_key = b"john-secret-key" # secret key
request_method = "GET" # HTTP method
request_path = "/get" # Route URI
algorithm= "hmac-sha256" # can use other algorithms in allowed_algorithms
# get current datetime in GMT
# note: the signature will become invalid after the clock skew (default 300s)
# you can regenerate the signature after it becomes invalid, or increase the clock
# skew to prolong the validity within the advised security boundary
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
# construct the signing string (ordered)
# the date and any subsequent custom headers should be lowercased and separated by a
# single space character, i.e. `<key>:<space><value>`
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6
signing_string = (
f"{key_id}\n"
f"{request_method} {request_path}\n"
f"date: {gmt_time}\n"
)
# create signature
signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest()
signature_base64 = base64.b64encode(signature).decode('utf-8')
# construct the request headers
headers = {
"Date": gmt_time,
"Authorization": (
f'Signature keyId="{key_id}",algorithm="{algorithm}",'
f'headers="@request-target date",'
f'signature="{signature_base64}"'
)
}
# print headers
print(headers)
```
运行脚本:
```shell
python3 hmac-sig-header-gen.py
```
您应该看到打印的请求标头:
```text
{'Date': 'Fri, 06 Sep 2024 06:41:29 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="'}
```
使用生成的标头,向路由发送请求:
```shell
curl -X GET "http://127.0.0.1:9080/get" \
-H "Date: Fri, 06 Sep 2024 06:41:29 GMT" \
-H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="'
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date\",signature=\"wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM=\"",
"Date": "Fri, 06 Sep 2024 06:41:29 GMT",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66d96513-2e52d4f35c9b6a2772d667ea",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-hmac-auth",
"X-Consumer-Custom-Id": "495aec6a",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 34.0.34.160",
"url": "http://127.0.0.1/get"
}
```
### Hide Authorization Information From Upstream
As seen the in the [last example](#implement-hmac-authentication-on-a-route), the `Authorization` header passed to the Upstream includes the signature and all other details. This could potentially introduce security risks.
The following example demonstrates how to prevent these information from being sent to the Upstream service.
Update the plugin configuration to set `hide_credentials` to `true`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/hmac-auth-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"hmac-auth": {
"hide_credentials": true
}
}
}'
```
Send a request to the route:
```shell
curl -X GET "http://127.0.0.1:9080/get" \
-H "Date: Fri, 06 Sep 2024 06:41:29 GMT" \
-H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="'
```
You should see an `HTTP/1.1 200 OK` response and notice the `Authorization` header is entirely removed:
```json
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66d96513-2e52d4f35c9b6a2772d667ea",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-hmac-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 34.0.34.160",
"url": "http://127.0.0.1/get"
}
```
### Enable Body Validation
The following example demonstrates how to enable body validation to ensure the integrity of the request body.
Create a consumer `john`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
为消费者创建 `hmac-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-hmac-auth",
"plugins": {
"hmac-auth": {
"key_id": "john-key",
"secret_key": "john-secret-key"
}
}
}'
```
Create a Route with the `hmac-auth` plugin as such:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "hmac-auth-route",
"uri": "/post",
"methods": ["POST"],
"plugins": {
"hmac-auth": {
"validate_request_body": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
生成签名。您可以使用以下 Python 代码片段或其他技术栈:
```python title="hmac-sig-digest-header-gen.py"
import hmac
import hashlib
import base64
from datetime import datetime, timezone
key_id = "john-key" # key id
secret_key = b"john-secret-key" # secret key
request_method = "POST" # HTTP method
request_path = "/post" # Route URI
algorithm= "hmac-sha256" # can use other algorithms in allowed_algorithms
body = '{"name": "world"}' # example request body
# get current datetime in GMT
# note: the signature will become invalid after the clock skew (default 300s).
# you can regenerate the signature after it becomes invalid, or increase the clock
# skew to prolong the validity within the advised security boundary
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
# construct the signing string (ordered)
# the date and any subsequent custom headers should be lowercased and separated by a
# single space character, i.e. `<key>:<space><value>`
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6
signing_string = (
f"{key_id}\n"
f"{request_method} {request_path}\n"
f"date: {gmt_time}\n"
)
# create signature
signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest()
signature_base64 = base64.b64encode(signature).decode('utf-8')
# create the SHA-256 digest of the request body and base64 encode it
body_digest = hashlib.sha256(body.encode('utf-8')).digest()
body_digest_base64 = base64.b64encode(body_digest).decode('utf-8')
# construct the request headers
headers = {
"Date": gmt_time,
"Digest": f"SHA-256={body_digest_base64}",
"Authorization": (
f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
f'headers="@request-target date",'
f'signature="{signature_base64}"'
)
}
# print headers
print(headers)
```
运行脚本:
```shell
python3 hmac-sig-digest-header-gen.py
```
您应该看到打印的请求标头:
```text
{'Date': 'Fri, 06 Sep 2024 09:16:16 GMT', 'Digest': 'SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="'}
```
使用生成的标头,向路由发送请求:
```shell
curl "http://127.0.0.1:9080/post" -X POST \
-H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \
-H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-d '{"name": "world"}'
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"name\": \"world\"}": ""
},
"headers": {
"Accept": "*/*",
"Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date\",signature=\"rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE=\"",
"Content-Length": "17",
"Content-Type": "application/x-www-form-urlencoded",
"Date": "Fri, 06 Sep 2024 09:16:16 GMT",
"Digest": "SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66d978c3-49f929ad5237da5340bbbeb4",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-hmac-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"origin": "192.168.65.1, 34.0.34.160",
"url": "http://127.0.0.1/post"
}
```
如果您发送的请求没有摘要或摘要无效:
```shell
curl "http://127.0.0.1:9080/post" -X POST \
-H "Date: Fri, 06 Sep 2024 09:16:16 GMT" \
-H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \
-H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="rjS6NxOBKmzS8CZL05uLiAfE16hXdIpMD/L/HukOTYE="' \
-d '{"name": "world"}'
```
您应该看到一个 `HTTP/1.1 401 Unauthorized` 响应,其中包含以下消息:
```text
{"message":"client request can't be validated"}
```
### 强制签名标头
以下示例演示了如何强制在请求的 HMAC 签名中对某些标头进行签名。
创建消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
为消费者创建 `hmac-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-hmac-auth",
"plugins": {
"hmac-auth": {
"key_id": "john-key",
"secret_key": "john-secret-key"
}
}
}'
```
使用 `hmac-auth` 插件创建路由,该插件要求 HMAC 签名中存在三个标头:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "hmac-auth-route",
"uri": "/get",
"methods": ["GET"],
"plugins": {
"hmac-auth": {
"signed_headers": ["date","x-custom-header-a","x-custom-header-b"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
生成签名。您可以使用以下 Python 代码片段或其他技术栈:
```python title="hmac-sig-req-header-gen.py"
import hmac
import hashlib
import base64
from datetime import datetime, timezone
key_id = "john-key" # key id
secret_key = b"john-secret-key" # secret key
request_method = "GET" # HTTP method
request_path = "/get" # Route URI
algorithm= "hmac-sha256" # can use other algorithms in allowed_algorithms
custom_header_a = "hello123" # required custom header
custom_header_b = "world456" # required custom header
# get current datetime in GMT
# note: the signature will become invalid after the clock skew (default 300s)
# you can regenerate the signature after it becomes invalid, or increase the clock
# skew to prolong the validity within the advised security boundary
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
# construct the signing string (ordered)
# the date and any subsequent custom headers should be lowercased and separated by a
# single space character, i.e. `<key>:<space><value>`
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6
signing_string = (
f"{key_id}\n"
f"{request_method} {request_path}\n"
f"date: {gmt_time}\n"
f"x-custom-header-a: {custom_header_a}\n"
f"x-custom-header-b: {custom_header_b}\n"
)
# create signature
signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest()
signature_base64 = base64.b64encode(signature).decode('utf-8')
# construct the request headers
headers = {
"Date": gmt_time,
"Authorization": (
f'Signature keyId="{key_id}",algorithm="hmac-sha256",'
f'headers="@request-target date x-custom-header-a x-custom-header-b",'
f'signature="{signature_base64}"'
),
"x-custom-header-a": custom_header_a,
"x-custom-header-b": custom_header_b
}
# print headers
print(headers)
```
运行脚本:
```shell
python3 hmac-sig-req-header-gen.py
```
您应该看到打印的请求标头:
```text
{'Date': 'Fri, 06 Sep 2024 09:58:49 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE="', 'x-custom-header-a': 'hello123', 'x-custom-header-b': 'world456'}
```
使用生成的标头,向路由发送请求:
```shell
curl -X GET "http://127.0.0.1:9080/get" \
-H "Date: Fri, 06 Sep 2024 09:58:49 GMT" \
-H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE="' \
-H "x-custom-header-a: hello123" \
-H "x-custom-header-b: world456"
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date x-custom-header-a x-custom-header-b\",signature=\"MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE=\"",
"Date": "Fri, 06 Sep 2024 09:58:49 GMT",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66d98196-64a58db25ece71c077999ecd",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-hmac-auth",
"X-Custom-Header-A": "hello123",
"X-Custom-Header-B": "world456",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 103.97.2.206",
"url": "http://127.0.0.1/get"
}
```
### 匿名消费者的速率限制
以下示例演示了如何为常规消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证,配额较少。
创建常规消费者 `john`,并配置 `limit-count` 插件,以允许 30 秒内的配额为 3
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
为消费者 `john` 创建 `hmac-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-hmac-auth",
"plugins": {
"hmac-auth": {
"key_id": "john-key",
"secret_key": "john-secret-key"
}
}
}'
```
创建匿名用户 `anonymous`,并配置 `limit-count` 插件,以允许 30 秒内配额为 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
创建路由并配置 `hmac-auth` 插件以接受匿名消费者 `anonymous` 绕过身份验证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "hmac-auth-route",
"uri": "/get",
"methods": ["GET"],
"plugins": {
"hmac-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
生成签名。您可以使用以下 Python 代码片段或其他技术栈:
```python title="hmac-sig-header-gen.py"
import hmac
import hashlib
import base64
from datetime import datetime, timezone
key_id = "john-key" # key id
secret_key = b"john-secret-key" # secret key
request_method = "GET" # HTTP method
request_path = "/get" # Route URI
algorithm= "hmac-sha256" # can use other algorithms in allowed_algorithms
# get current datetime in GMT
# note: the signature will become invalid after the clock skew (default 300s)
# you can regenerate the signature after it becomes invalid, or increase the clock
# skew to prolong the validity within the advised security boundary
gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
# construct the signing string (ordered)
# the date and any subsequent custom headers should be lowercased and separated by a
# single space character, i.e. `<key>:<space><value>`
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6
signing_string = (
f"{key_id}\n"
f"{request_method} {request_path}\n"
f"date: {gmt_time}\n"
)
# create signature
signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest()
signature_base64 = base64.b64encode(signature).decode('utf-8')
# construct the request headers
headers = {
"Date": gmt_time,
"Authorization": (
f'Signature keyId="{key_id}",algorithm="{algorithm}",'
f'headers="@request-target date",'
f'signature="{signature_base64}"'
)
}
# print headers
print(headers)
```
运行脚本:
```shell
python3 hmac-sig-header-gen.py
```
您应该看到打印的请求标头:
```text
{'Date': 'Mon, 21 Oct 2024 17:31:18 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="ztFfl9w7LmCrIuPjRC/DWSF4gN6Bt8dBBz4y+u1pzt8="'}
```
使用生成的标头发送五个连续的请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H "Date: Mon, 21 Oct 2024 17:31:18 GMT" -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="ztFfl9w7LmCrIuPjRC/DWSF4gN6Bt8dBBz4y+u1pzt8="' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 5 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200: 3, 429: 2
```
发送五个匿名请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,表明只有一个请求成功:
```text
200: 1, 429: 4
```

View File

@@ -0,0 +1,124 @@
---
title: http-dubbo
keywords:
- Apache APISIX
- API 网关
- Plugin
- http-dubbo
- http to dubbo
description: 本文介绍了关于 Apache APISIX `http-dubbo` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`http-dubbo` 插件可以将 http 请求 encode 为 dubbo 协议转发给上游服务(注意:在 dubbo2.x 时上游服务的序列化类型必须是 fastjson)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------------ | ------- |-----| ------ | ----------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| service_name | string | 是 | | | dubbo 服务名 |
| service_version | string | 否 | 0.0.0 | | dubbo 服务版本 默认 0.0.0 |
| method | string | 是 | | | dubbo 服务方法名 |
| params_type_desc | string | 否 | | | dubbo 服务方法签名描述,入参如果是 void 可不填写 |
| serialization_header_key | string | 否 | | | 插件会读取该请求头判断 body 是否已经按照 dubbo 协议序列化完毕。如果该请求头的值为 true 则插件不会更改 body 内容,直接把他当作 dubbo 请求参数。如果为 false 则要求开发者按照 dubbo 泛化调用的格式传递参数,由插件进行序列化。注意:由于 lua 和 java 的插件序列化精度不同,可能会导致参数精度不同。 |
| serialized | boolean | 否 | false | [true, false] | 和`serialization_header_key`一样。优先级低于`serialization_header_key` |
| connect_timeout | number | 否 | 6000 | | 上游服务 tcp connect_timeout |
| read_timeout | number | 否 | 6000 | | 上游服务 tcp read_timeout |
| send_timeout | number | 否 | 6000 | | 上游服务 tcp send_timeout |
## 启用插件
以下示例展示了如何在指定路由中启用 `http-dubbo` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/TestService/testMethod",
"plugins": {
"http-dubbo": {
"method": "testMethod",
"params_type_desc": "Ljava/lang/Long;Ljava/lang/Integer;",
"serialized": true,
"service_name": "com.xxx.xxx.TestService",
"service_version": "0.0.0"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl --location 'http://127.0.0.1:9080/TestService/testMethod' \
--data '1
2'
```
## 如何获取 params_type_desc
```java
Method[] declaredMethods = YourService.class.getDeclaredMethods();
String params_type_desc = ReflectUtils.getDesc(Arrays.stream(declaredMethods).filter(it->it.getName().equals("yourmethod")).findAny().get().getParameterTypes());
//方法重载情况下需要找自己需要暴露的方法 ReflectUtils 为 dubbo 实现
```
## 如何按照 dubbo 协议使用 json 进行序列化
为了防止精度丢失。我们推荐使用序列化好的 body 进行请求。
dubbo 的 fastjson 序列化规则如下:
- 每个参数之间使用 toJSONString 转化为 JSON 字符串
- 每个参数之间使用换行符 `\n` 分隔
部分语言和库在字符串或数字调用 toJSONString 后结果是不变的这可能需要你手动处理一些特殊情况例如:
- 字符串 `abc"` 需要被 encode 为 `"abc\""`
- 字符串 `123` 需要被 encode 为 `"123"`
抽象类,父类或者泛型作为入参签名,入参需要具体类型时。序列化需要写入具体的类型信息具体参考 [WriteClassName](https://github.com/alibaba/fastjson/wiki/SerializerFeature_cn)
## 删除插件
当你需要禁用 `http-dubbo` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务。

View File

@@ -0,0 +1,191 @@
---
title: http-logger
keywords:
- Apache APISIX
- API 网关
- 插件
- HTTP Logger
- 日志
description: 本文介绍了 API 网关 Apache APISIX 的 http-logger 插件。使用该插件可以将 APISIX 的日志数据推送到 HTTP 或 HTTPS 服务器。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`http-logger` 插件可以将 APISIX 的日志数据推送到 HTTP 或 HTTPS 服务器。该插件提供了将日志数据请求作为 JSON 对象发送到监控工具或者其他 HTTP 服务器的功能。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|-------------------------| ------- |-----| ------------- | -------------------- | ------------------------------------------------ |
| uri | string | 是 | | | HTTP 或 HTTPS 服务器的 URI。 |
| auth_header | string | 否 | | | 授权 header如果需要。 |
| timeout | integer | 否 | 3 | [1,...] | 发送请求后保持连接处于活动状态的时间。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,将请求体包含在日志中。如果请求体太大而无法保存在内存中,由于 NGINX 的限制,无法记录。 |
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时,使用该属性并基于 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 进行过滤。如果存在,则仅在表达式计算结果为 `true` 时记录响应。 |
| concat_method | string | 否 | "json" | ["json", "new_line"] | 枚举类型: **json**:对所有待发日志使用 `json.encode` 编码。**new_line**:对每一条待发日志单独使用 `json.encode` 编码并使用 `\n` 连接起来。 |
| ssl_verify | boolean | 否 | false | [false, true] | 当设置为 `true` 时验证证书。 |
该插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免该插件频繁地提交数据。默认情况下每 `5` 秒钟或队列中的数据达到 `1000` 条时,批处理器会自动提交数据,如需了解更多信息或自定义配置,请参考 [Batch Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"service_id": "",
"apisix_latency": 100.99999809265,
"start_time": 1703907485819,
"latency": 101.99999809265,
"upstream_latency": 1,
"client_ip": "127.0.0.1",
"route_id": "1",
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"request": {
"headers": {
"host": "127.0.0.1:1984",
"content-type": "application/x-www-form-urlencoded",
"user-agent": "lua-resty-http/0.16.1 (Lua) ngx_lua/10025",
"content-length": "12"
},
"method": "POST",
"size": 194,
"url": "http://127.0.0.1:1984/hello?log_body=no",
"uri": "/hello?log_body=no",
"querystring": {
"log_body": "no"
}
},
"response": {
"headers": {
"content-type": "text/plain",
"connection": "close",
"content-length": "12",
"server": "APISIX/3.7.0"
},
"status": 200,
"size": 123
},
"upstream": "127.0.0.1:1982"
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../../../en/latest/apisix-variable.md) 或 [NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `http-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/http-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 启用插件
你可以通过如下命令在指定路由上启用 `http-logger` 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"http-logger": {
"uri": "http://mockbin.org/bin/:ID"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
[mockbin](http://mockbin.org/bin/create) 服务器用于模拟 HTTP 服务器,以方便查看 APISIX 生成的日志。
## 测试插件
你可以通过以下命令向 APISIX 发出请求,访问日志将记录在你的 `mockbin` 服务器中:
```shell
curl -i http://127.0.0.1:9080/hello
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,153 @@
---
title: ip-restriction
keywords:
- Apache APISIX
- API 网关
- Plugin
- IP restriction
- ip-restriction
description: ip-restriction 插件支持通过配置 IP 地址白名单或黑名单来限制 IP 地址对上游资源的访问。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/ip-restriction" />
</head>
## 描述
`ip-restriction` 插件支持通过配置 IP 地址白名单或黑名单来限制 IP 地址对上游资源的访问。限制 IP 对资源的访问有助于防止未经授权的访问并加强 API 安全性。
## 属性
| 参数名 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------- | ------------- | ------ | ------ | ------ | -------------------------------- |
| whitelist | array[string] | 否 | | | 要列入白名单的 IP 列表。支持 IPv4、IPv6 和 CIDR 表示法。 |
| blacklist | array[string] | 否 | | | 要列入黑名单的 IP 列表。支持 IPv4、IPv6 和 CIDR 表示法。 |
| message | string | 否 | "Your IP address is not allowed" | [1, 1024] | 在未允许的 IP 访问的情况下返回的信息。 |
:::note
`whitelist``blacklist` 至少配置一个,但不能同时配置。
:::
## 示例
以下示例演示了如何针对不同场景配置 `ip-restriction` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 通过白名单限制访问
以下示例演示了如何将有权访问上游资源的 IP 地址列表列入白名单,并自定义拒绝访问的错误消息。
使用 `ip-restriction` 插件创建路由,将一系列 IP 列入白名单,并自定义拒绝访问时的错误消息:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "ip-restriction-route",
"uri": "/anything",
"plugins": {
"ip-restriction": {
"whitelist": [
"192.168.0.1/24"
],
"message": "Access denied"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
如果您的 IP 被允许,您应该会收到 `HTTP/1.1 200 OK` 响应。如果不允许,您应该会收到 `HTTP/1.1 403 Forbidden` 响应,并显示以下错误消息:
```text
{"message":"Access denied"}
```
### 使用修改后的 IP 限制访问
以下示例演示了如何使用 `real-ip` 插件修改用于 IP 限制的 IP。如果 APISIX 位于反向代理之后,并且 APISIX 无法获得真实客户端 IP则此功能特别有用。
使用 `ip-restriction` 插件创建路由,将特定 IP 地址列入白名单,并从 URL 参数 `realip` 获取客户端 IP 地址:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "ip-restriction-route",
"uri": "/anything",
"plugins": {
"ip-restriction": {
"whitelist": [
"192.168.1.241"
]
},
"real-ip": {
"source": "arg_realip"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?realip=192.168.1.241"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
使用不同的 IP 地址发送另一个请求:
```shell
curl -i "http://127.0.0.1:9080/anything?realip=192.168.10.24"
```
您应该会收到 `HTTP/1.1 403 Forbidden` 响应。

View File

@@ -0,0 +1,199 @@
---
title: jwe-decrypt
keywords:
- Apache APISIX
- API 网关
- APISIX 插件
- JWE Decrypt
- jwe-decrypt
description: 本文档包含了关于 APISIX jwe-decrypt 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`jwe-decrypt` 插件,用于解密 APISIX [Service](../terminology/service.md) 或者 [Route](../terminology/route.md) 请求中的 [JWE](https://datatracker.ietf.org/doc/html/rfc7516) 授权请求头。
插件增加了一个 `/apisix/plugin/jwe/encrypt` 的内部 API提供给 JWE 加密使用。解密时,秘钥应该配置在 [Consumer](../terminology/consumer.md)内。
## 属性
Consumer 配置:
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|---------------|---------|-------|-------|-----|-------------------------------------------------------------|
| key | string | True | | | Consumer 的唯一 key |
| secret | string | True | | | 解密密钥,必须为 32 位。秘钥可以使用 [Secret](../terminology/secret.md) 资源保存在密钥管理服务中 |
| is_base64_encoded | boolean | False | false | | 如果密钥是 Base64 编码,则需要配置为 `true` |
:::note
注意,在启用 `is_base64_encoded` 后,你的 `secret` 长度可能会超过 32 位,你只需要保证在 Decode 后的长度仍然是 32 位即可。
:::
Route 配置:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|----------------|---------|-------|---------------|----------------------------------------------------------------------------|
| header | string | True | Authorization | 指定请求头,用于获取加密令牌 |
| forward_header | string | True | Authorization | 传递给 Upstream 的请求头名称 |
| strict | boolean | False | true | 如果为配置为 true请求中缺失 JWE token 则抛出 `403` 异常。如果为 `false`, 在缺失 JWE token 的情况下不会抛出异常 |
## 启用插件
首先,基于 `jwe-decrypt` 插件创建一个 Consumer并且配置解密密钥
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d '
{
"username": "jack",
"plugins": {
"jwe-decrypt": {
"key": "user-key",
"secret": "-secret-length-must-be-32-chars-"
}
}
}'
```
下一步,基于 `jwe-decrypt` 插件创建一个路由,用于解密 authorization 请求头:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/anything*",
"plugins": {
"jwe-decrypt": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
### 使用 JWE 加密数据
该插件创建了一个内部的 API `/apisix/plugin/jwe/encrypt` 以使用 JWE 进行加密。要公开它,需要创建一个对应的路由,并启用 [public-api](public-api.md) 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/jwenew -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/apisix/plugin/jwe/encrypt",
"plugins": {
"public-api": {}
}
}'
```
向 API 发送一个请求,将 Consumer 中配置的密钥,以参数的方式传递给 URI用于加密 payload 中的一些数据。
```shell
curl -G --data-urlencode 'payload={"uid":10000,"uname":"test"}' 'http://127.0.0.1:9080/apisix/plugin/jwe/encrypt?key=user-key' -i
```
您应该看到类似于如下内容的响应结果,其中 JWE 加密的数据位于响应体中:
```
HTTP/1.1 200 OK
Date: Mon, 25 Sep 2023 02:38:16 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.5.0
Apisix-Plugins: public-api
eyJhbGciOiJkaXIiLCJraWQiOiJ1c2VyLWtleSIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.hfzMJ0YfmbMcJ0ojgv4PYAHxPjlgMivmv35MiA.7nilnBt2dxLR_O6kf-HQUA
```
### 使用 JWE 解密数据
将加密数据放在 `Authorization` 请求头中,向 API 发起请求:
```shell
curl http://127.0.0.1:9080/anything/hello -H 'Authorization: eyJhbGciOiJkaXIiLCJraWQiOiJ1c2VyLWtleSIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.hfzMJ0YfmbMcJ0ojgv4PYAHxPjlgMivmv35MiA.7nilnBt2dxLR_O6kf-HQUA' -i
```
您应该可以看到类似于如下的响应内容,其中 `Authorization` 响应头显示了有效的解密内容:
```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 452
Connection: keep-alive
Date: Mon, 25 Sep 2023 02:38:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.5.0
Apisix-Plugins: jwe-decrypt
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "{\"uid\":10000,\"uname\":\"test\"}",
"Host": "127.0.0.1",
"User-Agent": "curl/8.1.2",
"X-Amzn-Trace-Id": "Root=1-6510f2c3-1586ec011a22b5094dbe1896",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 119.143.79.94",
"url": "http://127.0.0.1/anything/hello"
}
```
## 删除插件
要删除 `jwe-decrypt` 插件,您可以从插件配置中删除插件对应的 JSON 配置APISIX 会自动加载,您不需要重新启动即可生效。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/anything*",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```

View File

@@ -0,0 +1,907 @@
---
title: jwt-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- JWT Auth
- jwt-auth
description: jwt-auth 插件支持使用 JSON Web Token (JWT) 作为客户端在访问上游资源之前进行身份验证的机制。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`jwt-auth` 插件支持使用 [JSON Web Token (JWT)](https://jwt.io/) 作为客户端在访问上游资源之前进行身份验证的机制。
启用后,该插件会公开一个端点,供 [消费者](../terminology/consumer.md) 创建 JWT 凭据。该过程会生成一个令牌,客户端请求应携带该令牌以向 APISIX 标识自己。该令牌可以包含在请求 URL 查询字符串、请求标头或 cookie 中。然后APISIX 将验证该令牌以确定是否应允许或拒绝请求访问上游资源。
当消费者成功通过身份验证后APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username``X-Credential-Indentifier` 和其他消费者自定义标头(如已配置)。上游服务将能够区分消费者并根据需要实施其他逻辑。如果任何一个值不可用,则不会添加相应的标题。
## 属性
Consumer/Credential 端:
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------- | ------- | ----- | ------- | --------------------------- | ------------------------------------------------------------------------------------------------------------ |
| key | string | 是 | | | 消费者的唯一密钥。 |
| secret | string | 否 | | | 当使用对称算法时,用于对 JWT 进行签名和验证的共享密钥。使用 `HS256``HS512` 作为算法时必填。如果未指定,后台将会自动生成。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
| public_key | string | 否 | | | RSA 或 ECDSA 公钥, `algorithm` 属性选择 `RS256``ES256` 算法时必选。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
| algorithm | string | 否 | "HS256" | ["HS256", "HS512", "RS256", "ES256"] | 加密算法。 |
| exp | integer | 否 | 86400 | [1,...] | token 的超时时间。 |
| base64_secret | boolean | 否 | false | | 当设置为 `true` 时,密钥为 base64 编码。 |
| lifetime_grace_period | integer | 否 | 0 | [0,...] | 宽限期(以秒为单位)。用于解决生成 JWT 的服务器与验证 JWT 的服务器之间的时钟偏差。 |
| key_claim_name | string | 否 | key | | JWT payload 中的声明用于标识相关的秘密,例如 `iss`。 |
注意schema 中还定义了 `encrypt_fields = {"secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
Route 端:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ------ | ------ | ------ | ------------- |---------------------------------------------------------|
| header | string | 否 | authorization | 设置我们从哪个 header 获取 token。 |
| query | string | 否 | jwt | 设置我们从哪个 query string 获取 token优先级低于 header。 |
| cookie | string | 否 | jwt | 设置我们从哪个 cookie 获取 token优先级低于 query。 |
| hide_credentials | boolean | 否 | false | 如果为 true则不要将 header、query 或带有 JWT 的 cookie 传递给上游服务。 |
| key_claim_name | string | 否 | key | 包含用户密钥(对应消费者的密钥属性)的 JWT 声明的名称。|
| anonymous_consumer | string | 否 | false | 匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。 |
| store_in_ctx | boolean | 否 | false | 设置为 `true` 将会将 JWT 负载存储在请求上下文 (`ctx.jwt_auth_payload`) 中。这允许在同一请求上随后运行的低优先级插件检索和使用 JWT 令牌。 |
您可以使用 [HashiCorp Vault](https://www.vaultproject.io/) 实施 `jwt-auth`,以从其[加密的 KV 引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 使用 [APISIX Secret](../terminology/secret.md) 资源。
## 示例
以下示例演示了如何在不同场景中使用 `jwt-auth` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 使用 JWT 进行消费者身份验证
以下示例演示如何实现 JWT 进行消费者密钥身份验证。
创建消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `jwt-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret"
}
}
}'
```
使用 `jwt-auth` 插件创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
要为 `jack` 签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用的是 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* __Algorithm__ 下拉菜单中选择 __HS256__
* __Verify Signature__ 部分中的密钥更新为 `jack-hs256-secret`
* 使用消费者密钥 `jack-key` 更新有效 payload并在 UNIX 时间戳中添加 `exp``nbf`
您的 payload 应类似于以下内容:
```json
{
"key": "jack-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```text
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I
```
使用 `Authorization` 标头中的 JWT 向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"headers": {
"Accept": "*/*",
"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-jwt-auth",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
30 秒后,令牌将过期。使用相同令牌发送请求以验证:
```shell
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"failed to verify jwt"}
```
### 在请求标头、查询字符串或 Cookie 中携带 JWT
以下示例演示如何在指定的标头、查询字符串和 Cookie 中接受 JWT。
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `jwt-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret"
}
}
}'
```
创建一个带有 `jwt-auth` 插件的路由,并指定请求可以在标头、查询或 cookie 中携带令牌:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {
"header": "jwt-auth-header",
"query": "jwt-query",
"cookie": "jwt-cookie"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
要为 `jack` 签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用的是 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* 在 __Algorithm__ 下拉菜单中选择 __HS256__。
* 将 __Verify Signature__ 部分中的密钥更新为 `jack-hs256-secret`。
* 使用消费者密钥 `jack-key` 更新有效 payload并在 UNIX 时间戳中添加 `exp` 或 `nbf`。
您的有效 payload 应类似于以下内容:
```json
{
"key": "jack-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```text
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I
```
#### 使用标头中的 JWT 进行验证
发送标头中包含 JWT 的请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H "jwt-auth-header: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"Jwt-Auth-Header": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ",
...
},
...
}
```
#### 在查询字符串中使用 JWT 进行验证
在查询字符串中使用 JWT 发送请求:
```shell
curl -i "http://127.0.0.1:9080/get?jwt-query=${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {
"jwt-query": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ"
},
"headers": {
"Accept": "*/*",
...
},
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://127.0.0.1/get?jwt-query=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ"
}
```
#### 使用 Cookie 中的 JWT 进行验证
使用 cookie 中的 JWT 发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" --cookie jwt-cookie=${jwt_token}
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Cookie": "jwt-cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ",
...
},
...
}
```
### 管理环境变量中的机密
以下示例演示了如何将 `jwt-auth` 消费者密钥保存到环境变量并在配置中引用它。
APISIX 支持引用通过 [NGINX `env` 指令](https://nginx.org/en/docs/ngx_core_module.html#env) 配置的系统和用户环境变量。
将密钥保存到环境变量中:
```shell
JACK_JWT_AUTH_KEY=jack-key
```
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `jwt-auth` 凭证并在密钥中引用环境变量:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "$env://JACK_JWT_AUTH_KEY",
"secret": "jack-hs256-secret"
}
}
}'
```
创建路由并启用 `jwt-auth`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
要为 `jack` 签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* 在 __Algorithm__ 下拉列表中选择 __HS256__。
* 将 __Verify Signature__ 部分中的密钥更新为 `jack-hs256-secret` 。
* 使用消费者密钥 `jack-key` 更新有效 payload并在 UNIX 时间戳中添加 `exp` 或 `nbf`。
您的有效 payload 应类似于以下内容:
```json
{
"key": "jack-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```text
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I
```
发送标头中包含 JWT 的请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMzMxNTUsImtleSI6Imp3dC1rZXkifQ.jiKuaAJqHNSSQCjXRomwnQXmdkC5Wp5VDPRsJlh1WAQ",
...
},
...
}
```
### 在秘密管理器中管理秘密
以下示例演示了如何管理 [HashiCorp Vault](https://www.vaultproject.io) 中的 `jwt-auth` 消费者密钥并在插件配置中引用它。
在 Docker 中启动 Vault 开发服务器:
```shell
docker run -d \
--name vault \
-p 8200:8200 \
--cap-add IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=root \
-e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
vault:1.9.0 \
vault server -dev
```
APISIX 目前支持 [Vault KV 引擎版本 1](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1)。在 Vault 中启用它:
```shell
docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv"
```
您应该看到类似于以下内容的响应:
```text
Success! Enabled the kv secrets engine at: kv/
```
创建一个 secret 并配置 Vault 地址和其他连接信息:
```shell
curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"uri": "https://127.0.0.1:8200"
"prefix": "kv/apisix",
"token": "root"
}'
```
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `jwt-auth` 凭证并引用密钥中的秘密:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "$secret://vault/jwt/jack/jwt-key",
"secret": "vault-hs256-secret"
}
}
}'
```
创建路由并启用 `jwt-auth`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/get",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
在 Vault 中将 `jwt-auth` 键值设置为 `jwt-vault-key`
```shell
docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack jwt-key=jwt-vault-key"
```
您应该看到类似于以下内容的响应:
```text
Success! Data written to: kv/apisix/jack
```
要签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* 在 __Algorithm__ 下拉列表中选择 __HS256__。
* 将 __Verify Signature__ 部分中的密钥更新为 `vault-hs256-secret` 。
* 使用消费者密钥 `jwt-vault-key` 更新有效 payload并在 UNIX 时间戳中添加 `exp` 或 `nbf`。
您的有效 payload 应类似于以下内容:
```json
{
"key": "jwt-vault-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```text
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.faiN93LNP1lGSXqAb4empNJKMRWop8-KgnU58VQn1EE
```
使用令牌作为标头发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g",
...
},
...
}
```
### 使用 RS256 算法签署 JWT
以下示例演示了在实施 JWT 进行消费者身份验证时如何使用非对称算法(例如 RS256来签名和验证 JWT。您将使用 [openssl](https://openssl-library.org/source/) 生成 RSA 密钥对,并使用 [JWT.io](https://jwt.io/#debugger-io) 生成 JWT以更好地了解 JWT 的组成。
生成 2048 位的 RSA 私钥并提取对应的 PEM 格式的公钥:
```shell
openssl genrsa -out jwt-rsa256-private.pem 2048
openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem
```
您应该会看到在当前工作目录中生成了 `jwt-rsa256-private.pem` 和 `jwt-rsa256-public.pem` 。
访问 [JWT.io 的调试器](https://jwt.io/#debugger-io) 并执行以下操作:
* 在 __Algorithm__ 下拉列表中选择 __RS256__。
* 将 key 复制并粘贴到 __Verify Signature__ 部分。
* 使用与您想要使用的消费者密钥匹配的 `key` 更新有效 payload以及 UNIX 时间戳中的 `exp` 或 `nbf`。
配置应类似于以下内容:
<br />
<div style={{textAlign: 'center'}}>
<img
src="https://static.apiseven.com/uploads/2024/12/12/SRe7AXMw_jwt_token.png"
alt="complete configuration of JWT generation on jwt.io"
width="70%"
/>
</div>
<br />
复制左侧的 JWT 并保存到环境变量中:
```shell
jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ
```
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `jwt-auth` 凭证并配置 RSA 密钥:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnE0h4k/GWfEbYO/yE2MPjHtNKDLNz4mv1KNIPLxY2ccjPYOtjuug+iZ4MujLV59YfrHriTs0H8jweQfff3pRSMjyEK+4qWTY3TeKBXIEa3pVDeoedSJrgjLBVio6xH7et8ir+QScScfLaJHGB4/l3DDGyEhO782a9teY8brn5hsWX5uLmDJvxtTGAHYi847XOcx2UneW4tZ8wQ6JGBSiSg5qAHan4dFZ7CpixCNNqEcSK6EQ7lKOLeFGG8ys/dHBIEasU4oMlCuJH77+XQQ/shchy+vm9oZfP+grLZkV+nKAd8MQZsid7ZJ/fiB/BmnhGrjtIfh98jwxSx4DgdLhdwIDAQAB\n-----END PUBLIC KEY-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCcTSHiT8ZZ8Rtg7/ITYw+Me00oMs3Pia/Uo0g8vFjZxyM9g62O66D6Jngy6MtXn1h+seuJOzQfyPB5B99/elFIyPIQr7ipZNjdN4oFcgRrelUN6h51ImuCMsFWKjrEft63yKv5BJxJx8tokcYHj+XcMMbISE7vzZr215jxuufmGxZfm4uYMm/G1MYAdiLzjtc5zHZSd5bi1nzBDokYFKJKDmoAdqfh0VnsKmLEI02oRxIroRDuUo4t4UYbzKz90cEgRqxTigyUK4kfvv5dBD+yFyHL6+b2hl8/6CstmRX6coB3wxBmyJ3tkn9+IH8GaeEauO0h+H3yPDFLHgOB0uF3AgMBAAECggEARpY68Daw0Funzq5uN70r/3iLztSqx8hZpQEclXlF8wwQ6S33iqz1JSOMcwlZE7g9wfHd+jrHfndDypT4pVx7KxC86TZCghWuLrFvXqgwQM2dbcxGdwXVYZZEZAJsSeM19+/jYnFnl5ZoUVBMC4w79aX9j+O/6mKDUmjphHmxUuRCFjN0w7BRoYwmS796rSf1eoOcSXh2G9Ycc34DUFDfGpOzabndbmMfOz7W0DyUBG23fgLhNChTUGq8vMaqKXkQ8JKeKdEugSmRGz42HxjWoNlIGBDyB8tPNPT6SXsu/JBskdf9Gb71OWiub381oXC259sz+1K1REb1KSkgyC+bkQKBgQDKCnwXaf8aOIoJPCG53EqQfKScCIYQrvp1Uk3bs5tfYN4HcI3yAUnOqQ3Ux3eY9PfS37urlJXCfCbCnZ6P6xALZnN+aL2zWvZArlHvD6vnXiyevwK5IY+o2EW02h3A548wrGznQSsfX0tum22bEVlRuFfBbpZpizXwrV4ODSNhTwKBgQDGC27QQxah3yq6EbOhJJlJegjawVXEaEp/j4fD3qe/unLbUIFvCz6j9BAbgocDKzqXxlpTtIbnsesdLo7KM3MtYL0XO/87HIsBj9XCVgMkFCcM6YZ6fHnkJl0bs3haU4N9uI/wpokvfvXJp7iC9LUCseBdBj+N6T230HWiSbPjWQKBgQC8zzGKO/8vRNkSqkQmSczQ2/qE6p5G5w6eJy0lfOJdLswvDatJFpUf8PJA/6svoPYb9gOO5AtUNeuPAfeVLSnQTYzu+/kTrJTme0GMdAvE60gtjfmAgvGa64mw6gjWJk+1P92B+2/OIKMAmXXDbWIYMXqpBKzBs1vUMF/uJ68BlwKBgQDEivQem3YKj3/HyWmLstatpP7EmrqTgSzuC3OhX4b7L/5sySirG22/KKgTpSZ4bp5noeJiz/ZSWrAK9fmfkg/sKOV/+XsDHwCVPDnX86SKWbWnitp7FK2jTq94nlQC0H7edhvjqGLdUBJ9XoYu8MvzMLSJnXnVTHSDx832kU6FgQKBgQCbw4Eiu2IcOduIAokmsZl8Smh9ZeyhP2B/UBa1hsiPKQ6bw86QJr2OMbRXLBxtx+HYIfwDo4vXEE862PfoQyu6SjJBNmHiid7XcV06Z104UQNjP7IDLMMF+SASMqYoQWg/5chPfxBgIXnfWqw6TMmND3THY4Oj4Nhf4xeUg3HsaA==\n-----END PRIVATE KEY-----"
}
}
}'
```
:::tip
您应该在开始行之后和结束行之前添加换行符,例如`-----BEGIN PRIVATE KEY-----\n......\n-----END PRIVATE KEY -----`。
关键内容可以直接拼接。
:::
使用 `jwt-auth` 插件创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用 `Authorization` 标头中的 JWT 向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsImV4cCI6MTczNDIzMDQwMH0.XjqM0oszmCggwZs-8PUIlJv8wPJON1la2ET5v70E6TCE32Yq5ibrl-1azaK7IreAer3HtnVHeEfII2rR02v8xfR1TPIjU_oHov4qC-A4tLTbgqGVXI7fCy2WFm3PFh6MEKuRe6M3dCQtCAdkRRQrBr1gWFQZhV3TNeMmmtyIfuJpB7cp4DW5pYFsCcoE1Nw6Tz7dt8k0tPBTPI2Mv9AYfMJ30LHDscOaPNtz8YIk_TOkV9b9mhQudUJ7J_suCZMRxD3iL655jTp2gKsstGKdZa0_W9Reu4-HY3LSc5DS1XtfjuftpuUqgg9FvPU0mK_b0wT_Rq3lbYhcHb9GZ72qiQ",
...
}
}
```
### 将消费者自定义 ID 添加到标头
以下示例演示了如何将消费者自定义 ID 附加到 `Consumer-Custom-Id` 标头中经过身份验证的请求,该标头可用于根据需要实现其他逻辑。
创建一个带有自定义 ID 标签的消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"labels": {
"custom_id": "495aec6a"
}
}'
```
为消费者创建 `jwt-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret"
}
}
}'
```
使用 `jwt-auth` 创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-auth-route",
"uri": "/anything",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
要为 `jack` 签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用的是 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* 在 __Algorithm__ 下拉菜单中选择 __HS256__。
* 将 __Verify Signature__ 部分中的密钥更新为 `jack-hs256-secret` 。
* 使用消费者密钥 `jack-key` 更新有效 payload并在 UNIX 时间戳中添加 `exp` 或 `nbf` 。
您的有效 payload 应类似于以下内容:
```json
{
"key": "jack-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```text
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.0VDKUzNkSaa_H5g_rGNbNtDcKJ9fBGgcGC56AsVsV-I
```
使用 `Authorization` 标头中的 JWT 向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
```
您应该看到类似于以下内容的 `HTTP/1.1 200 OK` 响应,其中附加了 `X-Consumer-Custom-Id`
```json
{
"headers": {
"Accept": "*/*",
"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-jwt-auth",
"X-Consumer-Custom-Id": "495aec6a",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
### 匿名消费者的速率限制
以下示例演示了如何为普通消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证,并且配额较少。
创建一个普通消费者 `jack`,并配置 `limit-count` 插件,以允许 30 秒内的配额为 3
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
为消费者 `jack` 创建 `jwt-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-jwt-auth",
"plugins": {
"jwt-auth": {
"key": "jack-key",
"secret": "jack-hs256-secret"
}
}
}'
```
创建匿名用户 `anonymous`,并配置 `limit-count` 插件,以允许 30 秒内配额为 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
创建一个路由并配置 `jwt-auth` 插件以接受匿名消费者 `anonymous` 绕过身份验证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "jwt-auth-route",
"uri": "/anything",
"plugins": {
"jwt-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
要为 `jack` 签发 JWT您可以使用 [JWT.io 的调试器](https://jwt.io/#debugger-io) 或其他实用程序。如果您使用的是 [JWT.io 的调试器](https://jwt.io/#debugger-io),请执行以下操作:
* 在 __Algorithm__ 下拉菜单中选择 __HS256__。
* 将 __Verify Signature__ 部分中的密钥更新为 `jack-hs256-secret`。
* 使用角色 `user` 、权限 `read` 和消费者密钥 `jack-key` 以及 UNIX 时间戳中的 `exp` 或 `nbf` 更新有效 payload。
您的有效 payload 应类似于以下内容:
```json
{
"key": "jack-key",
"nbf": 1729132271
}
```
将生成的 JWT 复制到 __Encoded__ 部分并保存到变量中:
```shell
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.hjtSsEILpko14zb8-ibyxrB2tA5biYY9JrFm3do69vs
```
为了验证速率限制,请使用 jack 的 JWT 连续发送五个请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H "Authorization: ${jwt_token}" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 5 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200: 3, 429: 2
```
发送五个匿名请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,表明只有一个请求成功:
```text
200: 1, 429: 4
```

View File

@@ -0,0 +1,247 @@
---
title: kafka-logger
keywords:
- Apache APISIX
- API 网关
- Plugin
- Kafka Logger
description: API 网关 Apache APISIX 的 kafka-logger 插件用于将日志作为 JSON 对象推送到 Apache Kafka 集群中。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`kafka-logger` 插件用于将日志作为 JSON 对象推送到 Apache Kafka 集群中。可用作 `ngx_lua` NGINX 模块的 Kafka 客户端驱动程序。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | ------- | ------ | -------------- | --------------------- | ------------------------------------------------ |
| broker_list | object | 是 | | | 已废弃,现使用 `brokers` 属性代替。原指需要推送的 Kafka 的 broker 列表。 |
| brokers | array | 是 | | | 需要推送的 Kafka 的 broker 列表。 |
| brokers.host | string | 是 | | | Kafka broker 的节点 host 配置,例如 `192.168.1.1` |
| brokers.port | string | 是 | | | Kafka broker 的节点端口配置 |
| brokers.sasl_config | object | 否 | | | Kafka broker 中的 sasl_config |
| brokers.sasl_config.mechanism | string | 否 | "PLAIN" | ["PLAIN"] | Kafka broker 中的 sasl 认证机制 |
| brokers.sasl_config.user | string | 是 | | | Kafka broker 中 sasl 配置中的 user如果 sasl_config 存在,则必须填写 |
| brokers.sasl_config.password | string | 是 | | | Kafka broker 中 sasl 配置中的 password如果 sasl_config 存在,则必须填写 |
| kafka_topic | string | 是 | | | 需要推送的 topic。 |
| producer_type | string | 否 | async | ["async", "sync"] | 生产者发送消息的模式。 |
| required_acks | integer | 否 | 1 | [1, -1] | 生产者在确认一个请求发送完成之前需要收到的反馈信息的数量。该参数是为了保证发送请求的可靠性。该属性的配置与 Kafka `acks` 属性相同,具体配置请参考 [Apache Kafka 文档](https://kafka.apache.org/documentation/#producerconfigs_acks)。required_acks 还不支持为 0。 |
| key | string | 否 | | | 用于消息分区而分配的密钥。 |
| timeout | integer | 否 | 3 | [1,...] | 发送数据的超时时间。 |
| name | string | 否 | "kafka logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| meta_format | enum | 否 | "default" | ["default""origin"] | `default`:获取请求信息以默认的 JSON 编码方式。`origin`:获取请求信息以 HTTP 原始请求方式。更多信息,请参考 [meta_format](#meta_format-示例)。|
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含请求体。**注意**:如果请求体无法完全存放在内存中,由于 NGINX 的限制APISIX 无法将它记录下来。|
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时进行过滤。只有当此处设置的表达式计算结果为 `true` 时,才会记录请求体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
| max_req_body_bytes | integer | 否 | 524288 | >=1 | 允许的最大请求正文(以字节为单位)。在此限制内的请求体将被推送到 Kafka。如果大小超过配置值则正文在推送到 Kafka 之前将被截断。 |
| include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤。只有当此处设置的表达式计算结果为 `true` 时才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。|
| max_resp_body_bytes | integer | 否 | 524288 | >=1 | 允许的最大响应正文(以字节为单位)。低于此限制的响应主体将被推送到 Kafka。如果大小超过配置值则正文在推送到 Kafka 之前将被截断。 |
| cluster_name | integer | 否 | 1 | [0,...] | Kafka 集群的名称,当有两个及以上 Kafka 集群时使用。只有当 `producer_type` 设为 `async` 模式时才可以使用该属性。|
| producer_batch_num | integer | 否 | 200 | [1,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `batch_num` 参数,聚合消息批量提交,单位为消息条数。 |
| producer_batch_size | integer | 否 | 1048576 | [0,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `batch_size` 参数,单位为字节。 |
| producer_max_buffering | integer | 否 | 50000 | [1,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `max_buffering` 参数,表示最大缓冲区,单位为条。 |
| producer_time_linger | integer | 否 | 1 | [1,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `flush_time` 参数,单位为秒。|
| meta_refresh_interval | integer | 否 | 30 | [1,...] | 对应 [lua-resty-kafka](https://github.com/doujiang24/lua-resty-kafka) 中的 `refresh_interval` 参数,用于指定自动刷新 metadata 的间隔时长,单位为秒。 |
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。
:::tip 提示
数据首先写入缓冲区。当缓冲区超过 `batch_max_size``buffer_duration` 设置的值时,则会将数据发送到 Kafka 服务器并刷新缓冲区。
如果发送成功,则返回 `true`。如果出现错误,则返回 `nil`,并带有描述错误的字符串 `buffer overflow`
:::
### meta_format 示例
- `default`:
```json
{
"upstream": "127.0.0.1:1980",
"start_time": 1619414294760,
"client_ip": "127.0.0.1",
"service_id": "",
"route_id": "1",
"request": {
"querystring": {
"ab": "cd"
},
"size": 90,
"uri": "/hello?ab=cd",
"url": "http://localhost:1984/hello?ab=cd",
"headers": {
"host": "localhost",
"content-length": "6",
"connection": "close"
},
"body": "abcdef",
"method": "GET"
},
"response": {
"headers": {
"connection": "close",
"content-type": "text/plain; charset=utf-8",
"date": "Mon, 26 Apr 2021 05:18:14 GMT",
"server": "APISIX/2.5",
"transfer-encoding": "chunked"
},
"size": 190,
"status": 200
},
"server": {
"hostname": "localhost",
"version": "2.5"
},
"latency": 0
}
```
- `origin`:
```http
GET /hello?ab=cd HTTP/1.1
host: localhost
content-length: 6
connection: close
abcdef
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ---------------- | ------- | ------ | ------------- |------------------------------------------------ |
| log_format | object | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../../../en/latest/apisix-variable.md) 或 [NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::note 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `kafka-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/kafka-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 如何启用
你可以通过如下命令在指定路由上启用 `kafka-logger` 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"kafka-logger": {
"brokers" : [
{
"host": "127.0.0.1",
"port": 9092
}
],
"kafka_topic" : "test2",
"key" : "key1"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
该插件还支持一次推送到多个 Broker示例如下
```json
"brokers" : [
{
"host" :"127.0.0.1",
"port" : 9092
},
{
"host" :"127.0.0.1",
"port" : 9093
}
],
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,570 @@
---
title: key-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- Key Auth
- key-auth
description: key-auth 插件支持使用身份验证密钥作为客户端在访问上游资源之前进行身份验证的机制。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/key-auth" />
</head>
## 描述
`key-auth` 插件支持使用身份验证密钥作为客户端在访问上游资源之前进行身份验证的机制。
要使用该插件,您需要在 [Consumers](../terminology/consumer.md) 上配置身份验证密钥,并在路由或服务上启用该插件。密钥可以包含在请求 URL 查询字符串或请求标头中。然后APISIX 将验证密钥以确定是否应允许或拒绝请求访问上游资源。
当消费者成功通过身份验证后APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username``X-Credential-Indentifier` 和其他消费者自定义标头(如果已配置)。上游服务将能够区分消费者并根据需要实现其他逻辑。如果这些值中的任何一个不可用,则不会添加相应的标头。
## 属性
Consumer/Credential 端:
| 名称 | 类型 | 必选项 | 描述 |
| ---- | ------ | ------ | ------------------------------------------------------------------------------------------------------------- |
| key | string | 是 | 不同的 Consumer 应有不同的 `key`,它应当是唯一的。如果多个 Consumer 使用了相同的 `key`,将会出现请求匹配异常。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
注意schema 中还定义了 `encrypt_fields = {"key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
Route 端:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ----------------- | ------ | ----- | ------ |----------------------------------------------------------------------------------------------------------------------------------------------------------|
| header | string | 否 | apikey | 设置我们从哪个 header 获取 key。 |
| query | string | 否 | apikey | 设置我们从哪个 query string 获取 key优先级低于 `header`。 |
| hide_credentials | boolean | 否 | false | 如果为 `true`,则不要将含有认证信息的 header 或 query string 传递给 Upstream。 |
## 示例
以下示例演示了如何在不同场景中使用 `key-auth` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 在路由上实现密钥认证
以下示例演示如何在路由上实现密钥认证并将密钥包含在请求标头中。
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
使用 `key-auth` 创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
#### 使用有效密钥进行验证
使用有效密钥发送请求至:
```shell
curl -i "http://127.0.0.1:9080/anything" -H 'apikey: jack-key'
```
您应该收到 `HTTP/1.1 200 OK` 响应。
#### 使用无效密钥进行验证
使用无效密钥发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -H 'apikey: wrong-key'
```
您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"Invalid API key in request"}
```
#### 无需密钥即可验证
无需密钥即可发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"Missing API key found in request"}
```
### 隐藏上游的身份验证信息
以下示例演示如何通过配置 `hide_credentials` 来防止密钥被发送到上游服务。默认情况下,身份验证密钥被转发到上游服务,这在某些情况下可能会导致安全风险。
创建一个消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
#### 不隐藏凭据
使用 `key-auth` 创建路由,并将 `hide_credentials` 配置为 `false` (默认配置)
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"hide_credentials": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送带有有效密钥的请求:
```shell
curl -i "http://127.0.0.1:9080/anything?apikey=jack-key"
```
您应该看到以下 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {
"auth": "jack-key"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Amzn-Trace-Id": "Root=1-6502d8a5-2194962a67aa21dd33f94bb2",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 103.248.35.179",
"url": "http://127.0.0.1/anything?apikey=jack-key"
}
```
注意凭证 `jack-key` 对于上游服务是可见的。
#### 隐藏凭据
将插件的 `hide_credentials` 更新为 `true`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/key-auth-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"key-auth": {
"hide_credentials": true
}
}
}'
```
发送带有有效密钥的请求:
```shell
curl -i "http://127.0.0.1:9080/anything?apikey=jack-key"
```
您应该看到以下 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Amzn-Trace-Id": "Root=1-6502d85c-16f34dbb5629a5960183e803",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 103.248.35.179",
"url": "http://127.0.0.1/anything"
}
```
注意凭证 `jack-key` 对上游服务不再可见。
### 演示标头和查询中的密钥优先级
以下示例演示了如何在路由上实现消费者的密钥身份验证,并自定义应包含密钥的 URL 参数。该示例还显示,当在标头和查询字符串中都配置了 API 密钥时,请求标头具有更高的优先级。
创建消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
使用 `key-auth` 创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"query": "auth"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
#### 使用有效密钥进行验证
使用有效密钥发送请求至:
```shell
curl -i "http://127.0.0.1:9080/anything?auth=jack-key"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
#### 使用无效密钥进行验证
使用无效密钥发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?auth=wrong-key"
```
您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应:
```text
{"message":"Invalid API key in request"}
```
#### 使用查询字符串中的有效密钥进行验证
但是,如果您在标头中包含有效密钥,而 URL 查询字符串中仍包含无效密钥:
```shell
curl -i "http://127.0.0.1:9080/anything?auth=wrong-key" -H 'apikey: jack-key'
```
您应该会看到 `HTTP/1.1 200 OK` 响应。这表明标头中包含的密钥始终具有更高的优先级。
### 将消费者自定义 ID 添加到标头
以下示例演示了如何在 `Consumer-Custom-Id` 标头中将消费者自定义 ID 附加到经过身份验证的请求,该 ID 可用于根据需要实现其他逻辑。
创建一个带有自定义 ID 标签的消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"labels": {
"custom_id": "495aec6a"
}
}'
```
Create `key-auth` credential for the consumer:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
Create a Route with `key-auth`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
To verify, send a request to the Route with the valid key:
```shell
curl -i "http://127.0.0.1:9080/anything?auth=jack-key"
```
You should see an `HTTP/1.1 200 OK` response similar to the following:
```json
{
"args": {
"auth": "jack-key"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea8d64-33df89052ae198a706e18c2a",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Consumer-Custom-Id": "495aec6a",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/anything?apikey=jack-key"
}
```
### 匿名消费者的速率限制
以下示例演示了如何为常规消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证,并且配额较少。
创建常规消费者 `jack` 并配置 `limit-count` 插件以允许 30 秒内的配额为 3
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
为消费者 `jack` 创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
创建匿名用户 `anonymous`,并配置 `limit-count`插件,以允许 30 秒内配额为 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
创建路由并配置 `key-auth` 插件以接受匿名消费者 `anonymous` 绕过身份验证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
为了验证,请使用 `jack` 的密钥发送五个连续的请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jack-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 5 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200: 3, 429: 2
```
发送五个匿名请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,表明只有一个请求成功:
```text
200: 1, 429: 4
```

View File

@@ -0,0 +1,167 @@
---
title: ldap-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- LDAP Authentication
- ldap-auth
description: 本篇文档介绍了 Apache APISIX ldap-auth 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`ldap-auth` 插件可用于给路由或服务添加 LDAP 身份认证,该插件使用 [lua-resty-ldap](https://github.com/api7/lua-resty-ldap) 连接 LDAP 服务器。
该插件需要与 Consumer 一起配合使用API 的调用方可以使用 [basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) 与 LDAP 服务器进行认证。
## 属性
Consumer 端:
| 名称 | 类型 | 必选项 | 描述 |
| ------- | ------ | -------- | -------------------------------------------------------------------------------- |
| user_dn | string | 是 | LDAP 客户端的 dn例如`cn=user01,ou=users,dc=example,dc=org`。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
Route 端:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|----------|---------|----------|---------|------------------------------------------------------------------------|
| base_dn | string | 是 | | LDAP 服务器的 dn例如`ou=users,dc=example,dc=org`。|
| ldap_uri | string | 是 | | LDAP 服务器的 URI。 |
| use_tls | boolean | 否 | false | 如果设置为 `true` 则表示启用 TLS。 |
| tls_verify| boolean | 否 | false | 是否校验 LDAP 服务器的证书。如果设置为 `true`,你必须设置 `config.yaml` 里面的 `ssl_trusted_certificate`,并且确保 `ldap_uri` 里的 host 和服务器证书中的 host 匹配。 |
| uid | string | 否 | cn | UID 属性。 |
## 启用插件
首先,你需要创建一个 Consumer 并在其中配置该插件,具体代码如下:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d '
{
"username": "foo",
"plugins": {
"ldap-auth": {
"user_dn": "cn=user01,ou=users,dc=example,dc=org"
}
}
}'
```
然后就可以在指定路由或服务中启用该插件,具体代码如下:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {
"ldap-auth": {
"base_dn": "ou=users,dc=example,dc=org",
"ldap_uri": "localhost:1389",
"uid": "cn"
},
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述方法配置插件后,可以通过以下命令测试插件:
```shell
curl -i -uuser01:password1 http://127.0.0.1:9080/hello
```
```shell
HTTP/1.1 200 OK
...
hello, world
```
如果授权信息请求头丢失或无效,则请求将被拒绝(如下展示了几种返回结果):
```shell
curl -i http://127.0.0.1:9080/hello
```
```shell
HTTP/1.1 401 Unauthorized
...
{"message":"Missing authorization in request"}
```
```shell
curl -i -uuser:password1 http://127.0.0.1:9080/hello
```
```shell
HTTP/1.1 401 Unauthorized
...
{"message":"Invalid user authorization"}
```
```shell
curl -i -uuser01:passwordfalse http://127.0.0.1:9080/hello
```
```shell
HTTP/1.1 401 Unauthorized
...
{"message":"Invalid user authorization"}
```
## 删除插件
当你需要禁用 `ldap-auth` 插件时,可以通过以下命令删除相应的 JSON 配置。APISIX 将自动重新加载,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,420 @@
---
title: limit-conn
keywords:
- APISIX
- API 网关
- Limit Connection
description: limit-conn 插件通过管理并发连接来限制请求速率。超过阈值的请求可能会被延迟或拒绝,以确保 API 使用受控并防止过载。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/limit-conn" />
</head>
## 描述
`limit-conn` 插件通过并发连接数来限制请求速率。超过阈值的请求将根据配置被延迟或拒绝,从而确保可控的资源使用并防止过载。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|------------|---------|----------|-------|----------------------------|------------------|
| conn | integer | 是 | | > 0 | 允许的最大并发请求数。超过配置的限制且低于`conn + burst`的请求将被延迟。|
| burst | integer | 是 | | >= 0 | 每秒允许延迟的过多并发请求数。超过限制的请求将被立即拒绝。|
| default_conn_delay | number | 是 | | > 0 | 允许超过`conn + burst`的并发请求的处理延迟(秒),可根据`only_use_default_delay`设置动态调整。|
| only_use_default_delay | boolean | 否 | false | | 如果为 false则根据请求超出`conn`限制的程度按比例延迟请求。拥塞越严重,延迟就越大。例如,当 `conn``5``burst``3``default_conn_delay``1`6 个并发请求将导致 1 秒的延迟7 个请求将导致 2 秒的延迟8 个请求将导致 3 秒的延迟,依此类推,直到达到 `conn + burst` 的总限制,超过此限制的请求将被拒绝。如果为 true则使用 `default_conn_delay` 延迟 `burst` 范围内的所有超额请求。超出 `conn + burst` 的请求将被立即拒绝。例如,当 `conn``5``burst``3``default_conn_delay``1`6、7 或 8 个并发请求都将延迟 1 秒。|
| key_type | string | 否 | var | ["var","var_combination"] | key 的类型。如果`key_type``var`,则 `key` 将被解释为变量。如果 `key_type``var_combination`,则 `key` 将被解释为变量的组合。 |
| key | string | 否 | remote_addr | | 用于计数请求的 key。如果 `key_type``var`,则 `key` 将被解释为变量。变量不需要以美元符号(`$`)为前缀。如果 `key_type``var_combination`,则 `key` 会被解释为变量的组合。所有变量都应该以美元符号 (`$`) 为前缀。例如,要配置 `key` 使用两个请求头 `custom-a``custom-b` 的组合,则 `key` 应该配置为 `$http_custom_a $http_custom_b`。|
| rejection_code | integer | 否 | 503 | [200,...,599] | 请求因超出阈值而被拒绝时返回的 HTTP 状态代码。|
| rejection_msg | string | 否 | | 非空 | 请求因超出阈值而被拒绝时返回的响应主体。|
| allow_degradation | boolean | 否 | false | | 如果为 true则允许 APISIX 在插件或其依赖项不可用时继续处理没有插件的请求。|
| policy | string | 否 | local | ["local","redis","redis-cluster"] | 速率限制计数器的策略。如果是 `local`,则计数器存储在本地内存中。如果是 `redis`,则计数器存储在 Redis 实例上。如果是 `redis-cluster`,则计数器存储在 Redis 集群中。|
| redis_host | string | 否 | | | Redis 节点的地址。当 `policy``redis` 时必填。 |
| redis_port | integer | 否 | 6379 | [1,...] | 当 `policy``redis`Redis 节点的端口。 |
| redis_username | string | 否 | | | 如果使用 Redis ACL则为 Redis 的用户名。如果使用旧式身份验证方法 `requirepass`,则仅配置 `redis_password`。当 `policy``redis` 时使用。 |
| redis_password | string | 否 | | | 当 `policy``redis``redis-cluster`Redis 节点的密码。 |
| redis_ssl | boolean | 否 | false |如果为 true则在 `policy``redis` 时使用 SSL 连接到 Redis 集群。|
| redis_ssl_verify | boolean | 否 | false | | 如果为 true则在 `policy``redis` 时验证服务器 SSL 证书。|
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy``redis`Redis 中的数据库编号。|
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy``redis``redis-cluster`Redis 超时值(以毫秒为单位)。 |
| redis_cluster_nodes | array[string] | 否 | | | 具有至少两个地址的 Redis 群集节点列表。当 policy 为 redis-cluster 时必填。 |
redis_cluster_name | string | 否 | | | | Redis 集群的名称。当 `policy``redis-cluster` 时必须使用。|
| redis_cluster_ssl | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster`时,使用 SSL 连接 Redis 集群。|
| redis_cluster_ssl_verify | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster` 时,验证服务器 SSL 证书。 |
## 示例
以下示例演示了如何在不同场景中配置 `limit-conn`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 通过远程地址应用速率限制
以下示例演示如何使用 `limit-conn` 通过 `remote_addr` 限制请求速率,并附带示例连接和突发阈值。
使用 `limit-conn` 插件创建路由,以允许 2 个并发请求和 1 个过多的并发请求。此外:
* 配置插件,允许超过 `conn + burst` 的并发请求有 0.1 秒的处理延迟。
* 将密钥类型设置为 `vars`,以将 `key` 解释为变量。
* 根据请求的 `remote_address` 计算速率限制计数。
* `policy` 设置为 `local`,以使用内存中的本地计数器。
* `rejected_code` 自定义为 `429`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"key_type": "var",
"key": "remote_addr",
"policy": "local",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送五个并发请求:
```shell
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
```
您应该会看到类似以下内容的响应,其中超过阈值的请求被拒绝:
```text
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
```
### 通过远程地址和消费者名称应用速率限制
以下示例演示如何使用 `limit-conn` 通过变量组合 `remote_addr``consumer_name` 对请求进行速率限制。
创建消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建第二个消费者 `jane`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jane"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
```
创建一个带有 `key-auth``limit-conn` 插件的路由,并在 `limit-conn` 插件中指定使用变量组合作为速率限制 key
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var_combination",
"key": "$remote_addr $consumer_name"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
作为消费者 `john` 发送五个并发请求:
```shell
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: john-key"'
```
您应该会看到类似以下内容的响应,其中超过阈值的请求被拒绝:
```text
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
```
接下来立刻以消费者 `jane` 的身份发送五个并发请求:
```shell
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: jane-key"'
```
您还应该看到类似以下内容的响应,其中过多的请求被拒绝:
```text
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
```
### 限制 WebSocket 连接速率
以下示例演示了如何使用 `limit-conn` 插件来限制并发 WebSocket 连接的数量。
启动 [上游 WebSocket 服务器](https://hub.docker.com/r/jmalloc/echo-server)
```shell
docker run -d \
-p 8080:8080 \
--name websocket-server \
--network=apisix-quickstart-net \
jmalloc/echo-server
```
创建到服务器 WebSocket 端点的路由,并为路由启用 WebSocket。相应地调整 WebSocket 服务器地址。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "ws-route",
"uri": "/.ws",
"plugins": {
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"key_type": "var",
"key": "remote_addr",
"rejected_code": 429
}
},
"enable_websocket": true,
"upstream": {
"type": "roundrobin",
"nodes": {
"websocket-server:8080": 1
}
}
}'
```
安装 WebSocket 客户端,例如 [websocat](https://github.com/vi/websocat),通过以下路由与 WebSocket 服务器建立连接:
```shell
websocat "ws://127.0.0.1:9080/.ws"
```
在终端中发送 `hello` 消息,您应该会看到 WebSocket 服务器回显相同的消息:
```text
Request served by 1cd244052136
hello
hello
```
再打开三个终端会话并运行:
```shell
websocat "ws://127.0.0.1:9080/.ws"
```
由于速率限制的影响,当您尝试与服务器建立 WebSocket 连接时,您应该会看到最后一个终端会话打印 `429 Too Many Requests`
### 使用 Redis 服务器在 APISIX 节点之间共享配额
以下示例演示了使用 Redis 服务器对多个 APISIX 节点之间的请求进行速率限制,以便不同的 APISIX 节点共享相同的速率限制配额。
在每个 APISIX 实例上,使用以下配置创建路由。相应地调整管理 API、Redis 主机、端口、密码和数据库的地址。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 1,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr",
"policy": "redis",
"redis_host": "192.168.xxx.xxx",
"redis_port": 6379,
"redis_password": "p@ssw0rd",
"redis_database": 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送五个并发请求:
```shell
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
```
您应该会看到类似以下内容的响应,其中超过阈值的请求被拒绝:
```text
Response: 200
Response: 200
Response: 429
Response: 429
Response: 429
```
这表明在不同 APISIX 实例中配置的两个路由共享相同的配额。
### 使用 Redis 集群在 APISIX 节点之间共享配额
您还可以使用 Redis 集群在多个 APISIX 节点之间应用相同的配额,以便不同的 APISIX 节点共享相同的速率限制配额。
确保您的 Redis 实例在 [集群模式](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster) 下运行。`limit-conn` 插件配置至少需要两个节点。
在每个 APISIX 实例上,使用以下配置创建一个路由。相应地调整管理 API 的地址、Redis 集群节点、密码、集群名称和 SSL 验证。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 1,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr",
"policy": "redis-cluster",
"redis_cluster_nodes": [
"192.168.xxx.xxx:6379",
"192.168.xxx.xxx:16379"
],
"redis_password": "p@ssw0rd",
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送五个并发请求:
```shell
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
```
您应该会看到类似以下内容的响应,其中超过阈值的请求被拒绝:
```text
Response: 200
Response: 200
Response: 429
Response: 429
Response: 429
```
这表明在不同的 APISIX 实例中配置的两条路由共享相同的配额。

View File

@@ -0,0 +1,508 @@
---
title: limit-count
keywords:
- APISIX
- API 网关
- Limit Count
- 速率限制
description: limit-count 插件使用固定窗口算法,通过给定时间间隔内的请求数量来限制请求速率。超过配置配额的请求将被拒绝。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/limit-count" />
</head>
## 描述
`limit-count` 插件使用固定窗口算法,通过给定时间间隔内的请求数量来限制请求速率。超过配置配额的请求将被拒绝。
您可能会在响应中看到以下速率限制标头:
* `X-RateLimit-Limit`:总配额
* `X-RateLimit-Remaining`:剩余配额
* `X-RateLimit-Reset`:计数器重置的剩余秒数
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------- | ------- | ---------- | ------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| count | integer | 是 | | > 0 | 给定时间间隔内允许的最大请求数。 |
| time_window | integer | 是 | | > 0 | 速率限制 `count` 对应的时间间隔(以秒为单位)。 |
| key_type | string | 否 | var | ["var","var_combination","constant"] | key 的类型。如果`key_type``var`,则 `key` 将被解释为变量。如果 `key_type``var_combination`,则 `key` 将被解释为变量的组合。如果 `key_type``constant`,则 `key` 将被解释为常量。 |
| key | string | 否 | remote_addr | | 用于计数请求的 key。如果 `key_type``var`,则 `key` 将被解释为变量。变量不需要以美元符号(`$`)为前缀。如果 `key_type``var_combination`,则 `key` 会被解释为变量的组合。所有变量都应该以美元符号 (`$`) 为前缀。例如,要配置 `key` 使用两个请求头 `custom-a``custom-b` 的组合,则 `key` 应该配置为 `$http_custom_a $http_custom_b`。如果 `key_type``constant`,则 `key` 会被解释为常量值。|
| rejection_code | integer | 否 | 503 | [200,...,599] | 请求因超出阈值而被拒绝时返回的 HTTP 状态代码。|
| rejection_msg | string | 否 | | 非空 | 请求因超出阈值而被拒绝时返回的响应主体。|
| policy | string | 否 | local | ["local","redis","redis-cluster"] | 速率限制计数器的策略。如果是 `local`,则计数器存储在本地内存中。如果是 `redis`,则计数器存储在 Redis 实例上。如果是 `redis-cluster`,则计数器存储在 Redis 集群中。|
| allow_degradation | boolean | 否 | false | | 如果为 true则允许 APISIX 在插件或其依赖项不可用时继续处理没有插件的请求。|
| show_limit_quota_header | boolean | 否 | true | | 如果为 true则在响应标头中包含 `X-RateLimit-Limit` 以显示总配额和 `X-RateLimit-Remaining` 以显示剩余配额。|
| group | string | 否 | | 非空 | 插件的 `group` ID以便同一 `group` 的路由可以共享相同的速率限制计数器。 |
| redis_host | string | 否 | | | Redis 节点的地址。当 `policy``redis` 时必填。 |
| redis_port | integer | 否 | 6379 | [1,...] | 当 `policy``redis`Redis 节点的端口。 |
| redis_username | string | 否 | | | 如果使用 Redis ACL则为 Redis 的用户名。如果使用旧式身份验证方法 `requirepass`,则仅配置 `redis_password`。当 `policy``redis` 时使用。 |
| redis_password | string | 否 | | | 当 `policy``redis``redis-cluster`Redis 节点的密码。 |
| redis_ssl | boolean | 否 | false |如果为 true则在 `policy``redis` 时使用 SSL 连接到 Redis 集群。|
| redis_ssl_verify | boolean | 否 | false | | 如果为 true则在 `policy``redis` 时验证服务器 SSL 证书。|
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy``redis`Redis 中的数据库编号。|
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy``redis``redis-cluster`Redis 超时值(以毫秒为单位)。 |
| redis_cluster_nodes | array[string] | 否 | | | 具有至少两个地址的 Redis 群集节点列表。当 policy 为 redis-cluster 时必填。 |
redis_cluster_name | string | 否 | | | | Redis 集群的名称。当 `policy``redis-cluster` 时必须使用。|
| redis_cluster_ssl | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster`时,使用 SSL 连接 Redis 集群。|
| redis_cluster_ssl_verify | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster` 时,验证服务器 SSL 证书。 |
## 示例
下面的示例演示了如何在不同情况下配置 `limit-count`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 按远程地址应用速率限制
下面的示例演示了通过单一变量 `remote_addr` 对请求进行速率限制。
创建一个带有 `limit-count` 插件的路由,允许在 30 秒窗口内为每个远程地址设置 1 个配额:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送验证请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该会看到 `HTTP/1.1 200 OK` 响应。
该请求已消耗了时间窗口允许的所有配额。如果您在相同的 30 秒时间间隔内再次发送该请求,您应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表示该请求超出了配额阈值。
### 通过远程地址和消费者名称应用速率限制
以下示例演示了通过变量 `remote_addr``consumer_name` 的组合对请求进行速率限制。它允许每个远程地址和每个消费者在 30 秒窗口内有 1 个配额。
创建消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建第二个消费者 `jane`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jane"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
```
创建一个带有 `key-auth``limit-count` 插件的路由,并在 `limit-count` 插件中指定使用变量组合作为速率限制键:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key_type": "var_combination",
"key": "$remote_addr $consumer_name"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
以消费者 `jane` 的身份发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key'
```
您应该会看到一个 `HTTP/1.1 200 OK` 响应以及相应的响应主体。
此请求已消耗了为时间窗口设置的所有配额。如果您在相同的 30 秒时间间隔内向消费者 `jane` 发送相同的请求,您应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,表示请求超出了配额阈值。
在相同的 30 秒时间间隔内向消费者 `john` 发送相同的请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key'
```
您应该看到一个 `HTTP/1.1 200 OK` 响应和相应的响应主体,表明请求不受速率限制。
在相同的 30 秒时间间隔内再次以消费者 `john` 的身份发送相同的请求,您应该收到一个 `HTTP/1.1 429 Too Many Requests` 响应。
这通过变量 `remote_addr``consumer_name` 的组合验证了插件速率限制。
### 在路由之间共享配额
以下示例通过配置 `limit-count` 插件的 `group` 演示了在多个路由之间共享速率限制配额。
请注意,同一 `group``limit-count` 插件的配置应该相同。为了避免更新异常和重复配置,您可以创建一个带有 `limit-count` 插件和上游的服务,以供路由连接。
创建服务:
```shell
curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-service",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"group": "srv1"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
创建两个路由,并将其 `service_id` 配置为 `limit-count-service`,以便它们对插件和上游共享相同的配置:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route-1",
"service_id": "limit-count-service",
"uri": "/get1",
"plugins": {
"proxy-rewrite": {
"uri": "/get"
}
}
}'
```
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route-2",
"service_id": "limit-count-service",
"uri": "/get2",
"plugins": {
"proxy-rewrite": {
"uri": "/get"
}
}
}'
```
:::note
[`proxy-rewrite`](./proxy-rewrite.md) 插件用于将 URI 重写为 `/get`,以便将请求转发到正确的端点。
:::
向路由 `/get1` 发送请求:
```shell
curl -i "http://127.0.0.1:9080/get1"
```
您应该会看到一个 `HTTP/1.1 200 OK` 响应以及相应的响应主体。
在相同的 30 秒时间间隔内向路由 `/get2` 发送相同的请求:
```shell
curl -i "http://127.0.0.1:9080/get2"
```
您应该收到 `HTTP/1.1 429 Too Many Requests` 响应,这验证两个路由共享相同的速率限制配额。
### 使用 Redis 服务器在 APISIX 节点之间共享配额
以下示例演示了使用 Redis 服务器对多个 APISIX 节点之间的请求进行速率限制,以便不同的 APISIX 节点共享相同的速率限制配额。
在每个 APISIX 实例上,使用以下配置创建一个路由。相应地调整管理 API 的地址、Redis 主机、端口、密码和数据库。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key": "remote_addr",
"policy": "redis",
"redis_host": "192.168.xxx.xxx",
"redis_port": 6379,
"redis_password": "p@ssw0rd",
"redis_database": 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向 APISIX 实例发送请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该会看到一个 `HTTP/1.1 200 OK` 响应以及相应的响应主体。
在相同的 30 秒时间间隔内向不同的 APISIX 实例发送相同的请求,您应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,验证在不同 APISIX 节点中配置的路由是否共享相同的配额。
### 使用 Redis 集群在 APISIX 节点之间共享配额
您还可以使用 Redis 集群在多个 APISIX 节点之间应用相同的配额,以便不同的 APISIX 节点共享相同的速率限制配额。
确保您的 Redis 实例在 [集群模式](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster) 下运行。`limit-count` 插件配置至少需要两个节点。
在每个 APISIX 实例上,使用以下配置创建路由。相应地调整管理 API 的地址、Redis 集群节点、密码、集群名称和 SSL 验证。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key": "remote_addr",
"policy": "redis-cluster",
"redis_cluster_nodes": [
"192.168.xxx.xxx:6379",
"192.168.xxx.xxx:16379"
],
"redis_password": "p@ssw0rd",
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向 APISIX 实例发送请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该会看到一个 `HTTP/1.1 200 OK` 响应以及相应的响应主体。
在相同的 30 秒时间间隔内向不同的 APISIX 实例发送相同的请求,您应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,验证在不同 APISIX 节点中配置的路由是否共享相同的配额。
### 使用匿名消费者进行速率限制
以下示例演示了如何为常规和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证并且配额较少。虽然此示例使用 [`key-auth`](./key-auth.md) 进行身份验证,但匿名消费者也可以使用 [`basic-auth`](./basic-auth.md)[`jwt-auth`](./jwt-auth.md)[`hmac-auth`](./hmac-auth.md) 进行配置。
创建一个消费者 `john`,并配置 `limit-count` 插件,以允许 30 秒内配额为 3
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
为消费者 `john` 创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建匿名用户 `anonymous`,并配置 `limit-count` 插件,以允许 30 秒内配额为 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
```
创建路由并配置 `key-auth` 插件以接受匿名消费者 `anonymous` 绕过身份验证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用 `john` 的密钥发送五个连续的请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 5 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200: 3, 429: 2
```
发送五个匿名请求:
```shell
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,表明只有一个请求成功:
```text
200: 1, 429: 4
```

View File

@@ -0,0 +1,289 @@
---
title: limit-req
keywords:
- APISIX
- API 网关
- Limit Request
- limit-req
description: limit-req 插件使用漏桶算法来限制请求的数量并允许节流。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/limit-req" />
</head>
## 描述
`limit-req` 插件使用 [leaky bucket](https://en.wikipedia.org/wiki/Leaky_bucket) 算法来限制请求的数量并允许节流。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------- | ------- | ------ | ------ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| rate | integer | True | | > 0 | 每秒允许的最大请求数。超过速率且低于突发的请求将被延迟。|
| bust | integer | True | | >= 0 | 每秒允许延迟的请求数,以进行限制。超过速率和突发的请求将被拒绝。|
| key_type | string | 否 | var | ["var","var_combination"] | key 的类型。如果 `key_type``var`,则 `key` 将被解释为变量。如果 `key_type``var_combination`,则 `key` 将被解释为变量的组合。 |
| key | string | 否 | remote_addr | | 用于计数请求的 key。如果 `key_type``var`,则 `key` 将被解释为变量。变量不需要以美元符号(`$`)为前缀。如果 `key_type``var_combination`,则 `key` 会被解释为变量的组合。所有变量都应该以美元符号 (`$`) 为前缀。例如,要配置 `key` 使用两个请求头 `custom-a``custom-b` 的组合,则 `key` 应该配置为 `$http_custom_a $http_custom_b`。如果 `key_type``constant`,则 `key` 会被解释为常量值。|
| rejection_code | integer | 否 | 503 | [200,...,599] | 请求因超出阈值而被拒绝时返回的 HTTP 状态代码。|
| rejection_msg | string | 否 | | 非空 | 请求因超出阈值而被拒绝时返回的响应主体。|
| nodelay | boolean | 否 | false | | 如果为 true则不要延迟突发阈值内的请求。 |
| allow_degradation | boolean | 否 | false | | 如果为 true则允许 APISIX 在插件或其依赖项不可用时继续处理没有插件的请求。|
| policy | string | 否 | local | ["local","redis","redis-cluster"] | 速率限制计数器的策略。如果是 `local`,则计数器存储在本地内存中。如果是 `redis`,则计数器存储在 Redis 实例上。如果是 `redis-cluster`,则计数器存储在 Redis 集群中。|
| allow_degradation | boolean | 否 | false | | 如果为 true则允许 APISIX 在插件或其依赖项不可用时继续处理没有插件的请求。|
| show_limit_quota_header | boolean | 否 | true | | 如果为 true则在响应标头中包含 `X-RateLimit-Limit` 以显示总配额和 `X-RateLimit-Remaining` 以显示剩余配额。|
| redis_host | string | 否 | | | Redis 节点的地址。当 `policy``redis` 时必填。 |
| redis_port | integer | 否 | 6379 | [1,...] | 当 `policy``redis`Redis 节点的端口。 |
| redis_username | string | 否 | | | 如果使用 Redis ACL则为 Redis 的用户名。如果使用旧式身份验证方法 `requirepass`,则仅配置 `redis_password`。当 `policy``redis` 时使用。 |
| redis_password | string | 否 | | | 当 `policy``redis``redis-cluster`Redis 节点的密码。 |
| redis_ssl | boolean | 否 | false |如果为 true则在 `policy``redis` 时使用 SSL 连接到 Redis 集群。|
| redis_ssl_verify | boolean | 否 | false | | 如果为 true则在 `policy``redis` 时验证服务器 SSL 证书。|
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy``redis`Redis 中的数据库编号。|
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy``redis``redis-cluster`Redis 超时值(以毫秒为单位)。 |
| redis_cluster_nodes | array[string] | 否 | | | 具有至少两个地址的 Redis 群集节点列表。当 policy 为 redis-cluster 时必填。 |
redis_cluster_name | string | 否 | | | | Redis 集群的名称。当 `policy``redis-cluster` 时必须使用。|
| redis_cluster_ssl | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster`时,使用 SSL 连接 Redis 集群。|
| redis_cluster_ssl_verify | boolean | 否 | false | | 如果为 `true`,当 `policy``redis-cluster` 时,验证服务器 SSL 证书。 |
## 示例
以下示例演示了如何在不同场景中配置 `limit-req`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 通过远程地址应用速率限制
以下示例演示了通过单个变量 `remote_addr` 对 HTTP 请求进行速率限制。
使用 `limit-req` 插件创建允许每个远程地址 1 QPS 的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '
{
"id": "limit-req-route",
"uri": "/get",
"plugins": {
"limit-req": {
"rate": 1,
"burst": 0,
"key": "remote_addr",
"key_type": "var",
"rejected_code": 429,
"nodelay": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该会看到一个 `HTTP/1.1 200 OK` 响应。
该请求已消耗了时间窗口允许的所有配额。如果您在同一秒内再次发送请求,您应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表示请求超出了配额阈值。
### 允许速率限制阈值
以下示例演示了如何配置 `burst` 以允许速率限制阈值超出配置的值并实现请求限制。您还将看到与未实施限制时的比较。
使用 `limit-req` 插件创建一个路由,允许每个远程地址 1 QPS并将 `burst` 设置为 1以允许 1 个超过 `rate` 的请求延迟处理:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-req-route",
"uri": "/get",
"plugins": {
"limit-req": {
"rate": 1,
"burst": 1,
"key": "remote_addr",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
生成三个对路由的请求:
```shell
resp=$(seq 3 | xargs -I{} curl -i "http://127.0.0.1:9080/get" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200 responses: $count_200 ; 429 responses: $count_429"
```
您可能会看到所有三个请求都成功:
```text
200 responses: 3 ; 429 responses: 0
```
现在,将 `burst` 更新为 0 或将 `nodelay` 设置为 `true`,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/limit-req-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"limit-req": {
"nodelay": true
}
}
}'
```
再次向路由生成三个请求:
```shell
resp=$(seq 3 | xargs -I{} curl -i "http://127.0.0.1:9080/get" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200 responses: $count_200 ; 429 responses: $count_429"
```
您应该会看到类似以下内容的响应,表明超出速率的请求已被拒绝:
```text
200 responses: 1 ; 429 responses: 2
```
### 通过远程地址和消费者名称应用速率限制
以下示例演示了通过变量组合 `remote_addr``consumer_name` 来限制请求的速率。
使用 `limit-req` 插件创建一个路由,允许每个远程地址和每个消费者 有 1 QPS。
创建消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建第二个消费者 `jane`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jane"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
```
创建一个带有 `key-auth``limit-req` 插件的路由,并在 `limit-req` 插件中指定使用变量组合作为速率限制 key
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "limit-req-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"limit-req": {
"rate": 1,
"burst": 0,
"key": "$remote_addr $consumer_name",
"key_type": "var_combination",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
同时发送两个请求,每个请求针对一个消费者:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key' & \
curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' &
```
您应该会收到两个请求的 `HTTP/1.1 200 OK`,表明请求未超过每个消费者的阈值。
如果您在同一秒内以任一消费者身份发送更多请求,应该会收到 `HTTP/1.1 429 Too Many Requests` 响应。
这验证了插件速率限制是通过变量 `remote_addr``consumer_name` 的来实现的。

View File

@@ -0,0 +1,113 @@
---
title: log-rotate
keywords:
- APISIX
- API 网关
- Plugin
- 日志切分
description: 云原生 API 网关 Apache APISIX log-rotate 插件用于定期切分日志目录下的访问日志和错误日志。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`log-rotate` 插件用于定期切分日志目录下的访问日志和错误日志。
你可以自定义日志轮换的频率以及要保留的日志数量。当日志数量超过限制时,旧的日志会被自动删除。
## 参数
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------ | ------- | ------ | ------- | ------------- | ---------------------------------------------------------------------------- |
| interval | integer | 是 | 60 * 60 | | 每间隔多长时间切分一次日志,以秒为单位。 |
| max_kept | integer | 是 | 24 * 7 | | 最多保留多少份历史日志,超过指定数量后,自动删除老文件。 |
| max_size | integer | 否 | -1 | | 日志文件超过指定大小时进行切分,单位为 Byte。如果 `max_size` 小于 0 或者根据 `interval` 计算的时间到达时,将不会根据 `max_size` 切分日志。 |
| enable_compression | boolean | 否 | false | [false, true] | 当设置为 `true` 时,启用日志文件压缩。该功能需要在系统中安装 `tar` 。 |
开启该插件后,就会按照参数自动切分日志文件了。比如以下示例是根据 `interval: 10``max_kept: 10` 得到的样本。
```shell
ll logs
```
```
total 44K
-rw-r--r--. 1 resty resty 0 Mar 20 20:33 2020-03-20_20-33-40_access.log
-rw-r--r--. 1 resty resty 2.8K Mar 20 20:33 2020-03-20_20-33-40_error.log
-rw-r--r--. 1 resty resty 0 Mar 20 20:33 2020-03-20_20-33-50_access.log
-rw-r--r--. 1 resty resty 2.4K Mar 20 20:33 2020-03-20_20-33-50_error.log
-rw-r--r--. 1 resty resty 0 Mar 20 20:33 2020-03-20_20-34-00_access.log
-rw-r--r--. 1 resty resty 2.4K Mar 20 20:34 2020-03-20_20-34-00_error.log
-rw-r--r--. 1 resty resty 0 Mar 20 20:34 2020-03-20_20-34-10_access.log
-rw-r--r--. 1 resty resty 2.4K Mar 20 20:34 2020-03-20_20-34-10_error.log
-rw-r--r--. 1 resty resty 0 Mar 20 20:34 access.log
-rw-r--r--. 1 resty resty 1.5K Mar 20 21:31 error.log
```
当开启日志文件压缩时,日志文件名称如下所示:
```shell
ll logs
```
```shell
total 10.5K
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:33 2020-03-20_20-33-50_access.log.tar.gz
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:33 2020-03-20_20-33-50_error.log.tar.gz
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:33 2020-03-20_20-34-00_access.log.tar.gz
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:34 2020-03-20_20-34-00_error.log.tar.gz
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:34 2020-03-20_20-34-10_access.log.tar.gz
-rw-r--r--. 1 resty resty 1.5K Mar 20 20:34 2020-03-20_20-34-10_error.log.tar.gz
-rw-r--r--. 1 resty resty 0 Mar 20 20:34 access.log
-rw-r--r--. 1 resty resty 1.5K Mar 20 21:31 error.log
```
## 启用插件
**该插件默认为禁用状态**,你可以在 `./conf/config.yaml` 中启用 `log-rotate` 插件,不需要在任何路由或服务中绑定。
```yaml title="./conf/config.yaml"
plugins:
# the plugins you enabled
- log-rotate
plugin_attr:
log-rotate:
interval: 3600 # rotate interval (unit: second)
max_kept: 168 # max number of log files will be kept
max_size: -1 # max size of log files will be kept
enable_compression: false # enable log file compression(gzip) or not, default false
```
配置完成,你需要重新加载 APISIX。
## 删除插件
当你不再需要该插件时,只需要在 `./conf/config.yaml` 中删除或注释该插件即可。
```yaml
plugins:
# the plugins you enabled
# - log-rotate
plugin_attr:
```

View File

@@ -0,0 +1,184 @@
---
title: loggly
keywords:
- APISIX
- API 网关
- Plugin
- SolarWinds Loggly
description: API 网关 Apache APISIX loggly 插件可用于将日志转发到 SolarWinds Loggly 进行分析和存储。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`loggly` 插件可用于将日志转发到 [SolarWinds Loggly](https://www.solarwinds.com/loggly) 进行分析和存储。
当启用插件时APISIX 会将请求上下文信息序列化为符合 [Loggly Syslog](https://documentation.solarwinds.com/en/success_center/loggly/content/admin/streaming-syslog-without-using-files.htm?cshid=loggly_streaming-syslog-without-using-files) 的数据格式,即具有 [RFC5424](https://datatracker.ietf.org/doc/html/rfc5424) 兼容标头的 Syslog。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|------------------------|---------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| customer_token | string | 是 | | 将日志发送到 Loggly 时使用的唯一标识符,以确保将日志发送到正确的组织帐户。 |
| severity | string (enum) | 否 | INFO | Syslog 日志事件的严重性级别。包括:`DEBUG``INFO``NOTICE``WARNING``ERR``CRIT``ALERT``EMEGR`。 |
| severity_map | object | 否 | nil | 一种将上游 HTTP 响应代码映射到 Syslog 中的方法。 `key-value`,其中 `key` 是 HTTP 响应代码,`value`是 Syslog 严重级别。例如`{"410": "CRIT"}`。 |
| tags | array | 否 | | 元数据将包含在任何事件日志中,以帮助进行分段和过滤。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | false | 当设置为 `true` 时,包含请求体。**注意**:如果请求体无法完全存放在内存中,由于 NGINX 的限制APISIX 无法将它记录下来。 |
| include_req_body_expr | array | 否 | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
该插件支持使用批处理器来聚合并批量处理条目(日志或数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
如果要生成用户令牌,请在 Loggly 系统中的 `<your assigned subdomain>/loggly.com/tokens` 设置,或者在系统中单击 `Logs > Source setup > Customer tokens`
### 默认日志格式示例
```text
<10>1 2024-01-06T06:50:51.739Z 127.0.0.1 apisix 58525 - [token-1@41058 tag="apisix"] {"service_id":"","server":{"version":"3.7.0","hostname":"localhost"},"apisix_latency":100.99985313416,"request":{"url":"http://127.0.0.1:1984/opentracing","headers":{"content-type":"application/x-www-form-urlencoded","user-agent":"lua-resty-http/0.16.1 (Lua) ngx_lua/10025","host":"127.0.0.1:1984"},"querystring":{},"uri":"/opentracing","size":155,"method":"GET"},"response":{"headers":{"content-type":"text/plain","server":"APISIX/3.7.0","transfer-encoding":"chunked","connection":"close"},"size":141,"status":200},"route_id":"1","latency":103.99985313416,"upstream_latency":3,"client_ip":"127.0.0.1","upstream":"127.0.0.1:1982","start_time":1704523851634}
```
## 插件元数据设置
你还可以通过插件元数据配置插件。详细配置如下:
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|------------|---------|-------|----------------------|--------------------------------|---------------------------------------------------------------------|
| host | string | 否 | "logs-01.loggly.com" | | 发送日志的主机的端点。 |
| port | integer | 否 | 514 | | 要连接的 Loggly 端口。仅用于 `syslog` 协议。 |
| timeout | integer | 否 | 5000 | | 发送数据请求超时时间(以毫秒为单位)。 |
| protocol | string | 否 | "syslog" | [ "syslog", "http", "https" ] | 将日志发送到 Loggly 的协议。 |
| log_format | object | 否 | nil | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
APISIX 支持 [Syslog](https://documentation.solarwinds.com/en/success_center/loggly/content/admin/streaming-syslog-without-using-files.htm)[HTTP/S](https://documentation.solarwinds.com/en/success_center/loggly/content/admin/http-bulk-endpoint.htm)(批量端点)协议将日志事件发送到 Loggly。**默认情况下 `protocol` 的值为 `syslog`**。该协议允许你通过一些细粒度的控制(基于上游 HTTP 响应代码的日志严重性映射)发送符合 RFC5424 的系统日志事件。但是 HTTP/S 批量端点非常适合以更快的传输速度发送更大量的日志事件。
:::note 注意
Syslog 协议允许你发送符合 RFC5424 的 syslog 事件并进行细粒度控制。但是在以快速传输速度发送大量日志时,使用 HTTP/S 批量端点会更好。你可以通过以下方式更新元数据以更新使用的协议:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/loggly \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"protocol": "http"
}'
```
:::
## 启用插件
以下示例展示了如何在指定路由上启用该插件:
**完整配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins":{
"loggly":{
"customer_token":"0e6fe4bf-376e-40f4-b25f-1d55cb29f5a2",
"tags":["apisix", "testroute"],
"severity":"info",
"severity_map":{
"503": "err",
"410": "alert"
},
"buffer_duration":60,
"max_retry_count":0,
"retry_delay":1,
"inactive_timeout":2,
"batch_max_size":10
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"127.0.0.1:80":1
}
},
"uri":"/index.html"
}'
```
**最小化配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins":{
"loggly":{
"customer_token":"0e6fe4bf-376e-40f4-b25f-1d55cb29f5a2",
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"127.0.0.1:80":1
}
},
"uri":"/index.html"
}'
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/index.html
```
发出请求后,你就可以在 Loggly 仪表盘上查看相关日志:
![Loggly Dashboard](../../../assets/images/plugin/loggly-dashboard.png)
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
```

View File

@@ -0,0 +1,407 @@
---
title: loki-logger
keywords:
- Apache APISIX
- API 网关
- Plugin
- Loki-logger
- Grafana Loki
description: loki-logger 插件通过 Loki HTTP API /loki/api/v1/push 将请求和响应日志批量推送到 Grafana Loki。该插件还支持自定义日志格式。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/loki-logger" />
</head>
## 描述
`loki-logger` 插件通过 [Loki HTTP API](https://grafana.com/docs/loki/latest/reference/loki-http-api/#loki-http-api) `/loki/api/v1/push` 将请求和响应日志批量推送到 [Grafana Loki](https://grafana.com/oss/loki/)。该插件还支持自定义日志格式。
启用后,插件会将请求上下文信息序列化为 [JSON object](https://grafana.com/docs/loki/latest/api/#push-log-entries-to-loki) 并将其添加到队列中,然后再将其推送到 Loki。有关更多详细信息请参阅批处理处理器 [batch processor](../batch-processor.md)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|--|---|---|---|---|
| end_addrs | array[string] | 是 | | | Loki API URL例如 `http://127.0.0.1:3100`。如果配置了多个端点,日志将被推送到列表中随机确定的端点。 |
| end_uri | string | 否 | /loki/api/v1/push | | Loki 提取端点的 URI 路径。 |
| tenant_id | string | 否 | fake | | Loki 租户 ID。根据 Loki 的 [多租户文档](https://grafana.com/docs/loki/latest/operations/multi-tenancy/#multi-tenancy),在单租户下默认值设置为 `fake`。 |
| headers | object | 否 | | | 请求头键值对(对 `X-Scope-OrgID``Content-Type` 的设置将会被忽略)。 |
| log_labels | object | 否 | {job = "apisix"} | | Loki 日志标签。支持 [NGINX 变量](https://nginx.org/en/docs/varindex.html) 和值中的常量字符串。变量应以 `$` 符号为前缀。例如,标签可以是 `{"origin" = "apisix"}``{"origin" = "$remote_addr"}`。|
| ssl_verify | boolean | 否 | true | | 如果为 true则验证 Loki 的 SSL 证书。|
| timeout | integer | 否 | 3000 | [1, 60000] | Loki 服务 HTTP 调用的超时时间(以毫秒为单位)。|
| keepalive | boolean | 否 | true | | 如果为 true则保持连接以应对多个请求。|
| keepalive_timeout | integer | 否 | 60000 | >=1000 | Keepalive 超时时间(以毫秒为单位)。|
| keepalive_pool | integer | 否 | 5 | >=1 | 连接池中的最大连接数。|
| log_format | object | 否 | | |自定义日志格式为 JSON 格式的键值对。值中支持 [APISIX 变量](../apisix-variable.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html)。 |
| name | string | 否 | loki-logger | | 批处理器插件的唯一标识符。如果使用 [Prometheus](./prometheus.md) 监控 APISIX 指标,则名称会导出到 `apisix_batch_process_entries`。 |
| include_req_body | boolean | 否 | false | | 如果为 true则将请求正文包含在日志中。请注意如果请求正文太大而无法保存在内存中则由于 NGINX 的限制而无法记录。 |
| include_req_body_expr | array[array] | 否 | | |一个或多个 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 形式条件的数组。在 `include_req_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录请求正文。|
| include_resp_body | boolean | 否 | false | | 如果为 true则将响应正文包含在日志中。|
| include_resp_body_expr | array[array] | 否 | | | 一个或多个 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 形式条件的数组。在 `include_resp_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录响应正文。|
该插件支持使用批处理器对条目(日志/数据)进行批量聚合和处理,避免了频繁提交数据的需求。批处理器每隔 `5` 秒或当队列中的数据达到 `1000` 时提交数据。有关更多信息或设置自定义配置,请参阅 [批处理器](../batch-processor.md#configuration)
## Plugin Metadata
您还可以使用 [Plugin Metadata](../terminology/plugin-metadata.md) 全局配置日志格式,该 Plugin Metadata 配置所有 `loki-logger` 插件实例的日志格式。如果在单个插件实例上配置的日志格式与在 Plugin Metadata 上配置的日志格式不同,则在单个插件实例上配置的日志格式优先。
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|------|------|----------|--|-------------|
| log_format | object | 否 | | 日志格式以 JSON 格式声明为键值对。值只支持字符串类型。可以通过在字符串前面加上 `$` 来使用 [APISIX 变量](../apisix-variable.md)[NGINX 变量](http://nginx.org/en/docs/varindex.html) 。 |
## 示例
下面的示例演示了如何为不同场景配置 `loki-logger` 插件。
为了遵循示例,请在 Docker 中启动一个示例 Loki 实例:
```shell
wget https://raw.githubusercontent.com/grafana/loki/v3.0.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml
docker run --name loki -d -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:3.2.1 -config.file=/mnt/config/loki-config.yaml
```
此外,启动 Grafana 实例来查看和可视化日志:
```shell
docker run -d --name=apisix-quickstart-grafana \
-p 3000:3000 \
grafana/grafana-oss
```
要连接 Loki 和 Grafana请访问 Grafana网址为 [`http://localhost:3000`](http://localhost:3000)。在 __Connections > Data sources__ 下,添加新数据源并选择 Loki。您的连接 URL 应遵循 `http://{your_ip_address}:3100` 的格式。保存新数据源时Grafana 还应测试连接,您应该会看到 Grafana 通知数据源已成功连接。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 以默认日志格式记录请求和响应
以下示例演示了如何在路由上配置 `loki-logger` 插件以记录通过路由的请求和响应。
使用 `loki-logger` 插件创建路由并配置 Loki 的地址:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "loki-logger-route",
"uri": "/anything",
"plugins": {
"loki-logger": {
"endpoint_addrs": ["http://192.168.1.5:3100"]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
向路由发送一些请求以生成日志条目:
```shell
curl "http://127.0.0.1:9080/anything"
```
您应该会收到所有请求的“HTTP/1.1 200 OK”响应。
导航到 [Grafana explore view](http://localhost:3000/explore) 并运行查询 `job = apisix`。您应该会看到与您的请求相对应的许多日志,例如以下内容:
```json
{
"route_id": "loki-logger-route",
"response": {
"status": 200,
"headers": {
"date": "Fri, 03 Jan 2025 03:54:26 GMT",
"server": "APISIX/3.11.0",
"access-control-allow-credentials": "true",
"content-length": "391",
"access-control-allow-origin": "*",
"content-type": "application/json",
"connection": "close"
},
"size": 619
},
"start_time": 1735876466,
"client_ip": "192.168.65.1",
"service_id": "",
"apisix_latency": 5.0000038146973,
"upstream": "34.197.122.172:80",
"upstream_latency": 666,
"server": {
"hostname": "0b9a772e68f8",
"version": "3.11.0"
},
"request": {
"headers": {
"user-agent": "curl/8.6.0",
"accept": "*/*",
"host": "127.0.0.1:9080"
},
"size": 85,
"method": "GET",
"url": "http://127.0.0.1:9080/anything",
"querystring": {},
"uri": "/anything"
},
"latency": 671.0000038147
}
```
这验证了 Loki 已从 APISIX 接收日志。您还可以在 Grafana 中创建仪表板,以进一步可视化和分析日志。
### 使用 Plugin Metadata 自定义日志格式
以下示例演示了如何使用 [Plugin Metadata](../terminology/plugin-metadata.md) 自定义日志格式。
使用 `loki-logger` 插件创建路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "loki-logger-route",
"uri": "/anything",
"plugins": {
"loki-logger": {
"endpoint_addrs": ["http://192.168.1.5:3100"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
`loki-logger` 配置 Plugin Metadata它将更新所有需要记录请求的路由的日志格式
```shell
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/loki-logger" -X PUT \
-H 'X-API-KEY: ${admin_key}' \
-d '{
"log_format": {
"host": "$host",
"client_ip": "$remote_addr",
"route_id": "$route_id",
"@timestamp": "$time_iso8601"
}
}'
```
向路由发送请求以生成新的日志条目:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [Grafana explore view](http://localhost:3000/explore) 并运行查询 `job = apisix`。您应该会看到与您的请求相对应的日志条目,类似于以下内容:
```json
{
"@timestamp":"2025-01-03T21:11:34+00:00",
"client_ip":"192.168.65.1",
"route_id":"loki-logger-route",
"host":"127.0.0.1"
}
```
如果路由上的插件指定了特定的日志格式,它将优先于 Plugin Metadata 中指定的日志格式。例如,按如下方式更新上一个路由上的插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/loki-logger-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"loki-logger": {
"log_format": {
"route_id": "$route_id",
"client_ip": "$remote_addr",
"@timestamp": "$time_iso8601"
}
}
}
}'
```
向路由发送请求以生成新的日志条目:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [Grafana explore view](http://localhost:3000/explore) 并重新运行查询 `job = apisix`。您应该会看到与您的请求相对应的日志条目,与路由上配置的格式一致,类似于以下内容:
```json
{
"client_ip":"192.168.65.1",
"route_id":"loki-logger-route",
"@timestamp":"2025-01-03T21:19:45+00:00"
}
```
### 有条件地记录请求主体
以下示例演示了如何有条件地记录请求主体。
使用 `loki-logger` 创建路由,仅在 URL 查询字符串 `log_body``yes` 时记录请求主体:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "loki-logger-route",
"uri": "/anything",
"plugins": {
"loki-logger": {
"endpoint_addrs": ["http://192.168.1.5:3100"],
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
使用满足条件的 URL 查询字符串向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [Grafana explore view](http://localhost:3000/explore) 并重新运行查询 `job = apisix`。您应该会看到与您的请求相对应的日志条目,与路由上配置的格式一致,类似于以下内容:
```json
{
"route_id": "loki-logger-route",
...,
"request": {
"headers": {
...
},
"body": "{\"env\": \"dev\"}",
"size": 182,
"method": "POST",
"url": "http://127.0.0.1:9080/anything?log_body=yes",
"querystring": {
"log_body": "yes"
},
"uri": "/anything?log_body=yes"
},
"latency": 809.99994277954
}
```
向路由发送一个没有任何 URL 查询字符串的请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
导航到 [Grafana explore view](http://localhost:3000/explore) 并重新运行查询 `job = apisix`。您应该会看到与您的请求相对应的日志条目,与路由上配置的格式一致,类似于以下内容:
```json
{
"route_id": "loki-logger-route",
...,
"request": {
"headers": {
...
},
"size": 169,
"method": "POST",
"url": "http://127.0.0.1:9080/anything",
"querystring": {},
"uri": "/anything"
},
"latency": 557.00016021729
}
```
:::info
如果您除了将 `include_req_body``include_resp_body` 设置为 `true` 之外还自定义了 `log_format`,则插件不会在日志中包含正文。
作为一种解决方法,您可以在日志格式中使用 NGINX 变量 `$request_body`,例如:
```json
{
"kafka-logger": {
...,
"log_format": {"body": "$request_body"}
}
}
```
:::
## FAQ
### 日志未正确推送
请查看 `error.log` 文件以获取此类日志。
```text
2023/04/30 13:45:46 [error] 19381#19381: *1075673 [lua] batch-processor.lua:95: Batch Processor[loki logger] failed to process entries: loki server returned status: 401, body: no org id, context: ngx.timer, client: 127.0.0.1, server: 0.0.0.0:9081
```
可以根据错误代码 `failed to process entries: loki server returned status: 401, body: no org id` 和 loki 服务器的响应正文来诊断错误。
### 当请求每秒 (RPS) 较高时出现错误?
- 请确保 `keepalive` 相关的配置已正确设置。有关更多信息,请参阅[属性](#属性)
- 请检查 `error.log` 中的日志,查找此类日志。
```text
2023/04/30 13:49:34 [error] 19381#19381: *1082680 [lua] batch-processor.lua:95: Batch Processor[loki logger] failed to process entries: loki server returned status: 429, body: Ingestion rate limit exceeded for user tenant_1 (limit: 4194304 bytes/sec) while attempting to ingest '1000' lines totaling '616307' bytes, reduce log volume or contact your Loki administrator to see if the limit can be increased, context: ngx.timer, client: 127.0.0.1, server: 0.0.0.0:9081
```
- 通常与高 QPS 相关的日志如上所示。错误信息为:`Ingestion rate limit exceeded for user tenant_1 (limit: 4194304 bytes/sec) while attempting to ingest '1000' lines totaling '616307' bytes, reduce log volume or contact your Loki administrator to see if the limit can be increased`。
- 请参考 [Loki 文档](https://grafana.com/docs/loki/latest/configuration/#limits_config) ,添加默认日志量和突发日志量的限制,例如 `ingestion_rate_mb` 和 `ingestion_burst_size_mb`。
在开发过程中进行测试时,将 `ingestion_burst_size_mb` 设置为 100 可以确保 APISIX 以至少 10000 RPS 的速率正确推送日志。

View File

@@ -0,0 +1,255 @@
---
title: mocking
keywords:
- Apache APISIX
- API 网关
- Plugin
- Mocking
description: 本文介绍了关于 Apache APISIX `mocking` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`mocking` 插件用于模拟 API。当执行该插件时它将随机返回指定格式的模拟数据并且请求不会转发到上游。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ------------- | -------| ----- | ---------------- | --------------------------------------------------------------------------- |
| delay | integer| 否 | | 延时返回的时间,单位为秒。 |
| response_status | integer| 否 | 200 | 返回响应的 HTTP 状态码。 |
| content_type | string | 否 | application/json | 返回响应的 Header `Content-Type`。 |
| response_example| string | 否 | | 返回响应的 Body支持使用变量例如 `$remote_addr $consumer_name`,与 `response_schema` 字段二选一。 |
| response_schema | object | 否 | | 指定响应的 `jsonschema` 对象,未指定 `response_example` 字段时生效。 |
| with_mock_header| boolean| 否 | true | 当设置为 `true` 时,将添加响应头 `x-mock-by: APISIX/{version}`。设置为 `false` 时则不添加该响应头。 |
| response_headers| object | 否 | | 要在模拟响应中添加的标头。示例:`{"X-Foo": "bar", "X-Few": "baz"}` |
JSON Schema 在其字段中支持以下类型:
- `string`
- `number`
- `integer`
- `boolean`
- `object`
- `array`
以下是一个 JSON Schema 示例:
```json
{
"properties":{
"field0":{
"example":"abcd",
"type":"string"
},
"field1":{
"example":123.12,
"type":"number"
},
"field3":{
"properties":{
"field3_1":{
"type":"string"
},
"field3_2":{
"properties":{
"field3_2_1":{
"example":true,
"type":"boolean"
},
"field3_2_2":{
"items":{
"example":155.55,
"type":"integer"
},
"type":"array"
}
},
"type":"object"
}
},
"type":"object"
},
"field2":{
"items":{
"type":"string"
},
"type":"array"
}
},
"type":"object"
}
```
以下为上述 JSON Schema 可能生成的返回对象:
```json
{
"field1": 123.12,
"field3": {
"field3_1": "LCFE0",
"field3_2": {
"field3_2_1": true,
"field3_2_2": [
155,
155
]
}
},
"field0": "abcd",
"field2": [
"sC"
]
}
```
## 启用插件
你可以通过如下命令在指定路由上启用 `mocking` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
"mocking": {
"delay": 1,
"content_type": "application/json",
"response_status": 200,
"response_schema": {
"properties":{
"field0":{
"example":"abcd",
"type":"string"
},
"field1":{
"example":123.12,
"type":"number"
},
"field3":{
"properties":{
"field3_1":{
"type":"string"
},
"field3_2":{
"properties":{
"field3_2_1":{
"example":true,
"type":"boolean"
},
"field3_2_2":{
"items":{
"example":155.55,
"type":"integer"
},
"type":"array"
}
},
"type":"object"
}
},
"type":"object"
},
"field2":{
"items":{
"type":"string"
},
"type":"array"
}
},
"type":"object"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下方式测试插件是否启用成功:
`mocking` 插件配置如下:
```JSON
{
"delay":0,
"content_type":"",
"with_mock_header":true,
"response_status":201,
"response_example":"{\"a\":1,\"b\":2}"
}
```
通过如下命令进行测试:
```shell
curl http://127.0.0.1:9080/test-mock -i
```
```Shell
HTTP/1.1 201 Created
Date: Fri, 14 Jan 2022 11:49:34 GMT
Content-Type: application/json;charset=utf8
Transfer-Encoding: chunked
Connection: keep-alive
x-mock-by: APISIX/2.10.0
Server: APISIX/2.10.0
{"a":1,"b":2}
```
## 删除插件
当你需要禁用 `mocking` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,174 @@
---
title: mqtt-proxy
keywords:
- APISIX
- API 网关
- Plugin
- MQTT Proxy
description: 本文档介绍了 Apache APISIX mqtt-proxy 插件的信息,通过 `mqtt-proxy` 插件可以使用 MQTT 的 `client_id` 进行动态负载平衡。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
通过 `mqtt-proxy` 插件可以使用 MQTT 的 `client_id` 进行动态负载平衡。它仅适用于 `stream` 模式。
这个插件支持 MQTT [3.1.*](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)[5.0]( https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html ) 两个协议。
## 属性
| 名称 | 类型 | 必选项 | 描述 |
| -------------- | ------- | ----- | ------------------------------------------------------ |
| protocol_name | string | 是 | 协议名称,正常情况下应为 `MQTT`。 |
| protocol_level | integer | 是 | 协议级别MQTT `3.1.*``4`MQTT `5.0` 应是`5`。 |
## 启用插件
为了启用该插件,需要先在配置文件(`./conf/config.yaml`)中加载 `stream_proxy` 相关配置。以下配置代表监听 `9100` TCP 端口:
```yaml title="./conf/config.yaml"
...
router:
http: 'radixtree_uri'
ssl: 'radixtree_sni'
stream_proxy: # TCP/UDP proxy
tcp: # TCP proxy port list
- 9100
dns_resolver:
...
```
现在你可以将请求发送到 `9100` 端口。
你可以创建一个 stream 路由并启用 `mqtt-proxy` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/stream_routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{
"host": "127.0.0.1",
"port": 1980,
"weight": 1
}]
}
}'
```
如果你在 macOS 中使用 Docker则 `host.docker.internal` 是 `host` 的正确属性。
该插件暴露了一个变量 `mqtt_client_id`,你可以使用它来通过客户端 ID 进行负载均衡。比如:
```shell
curl http://127.0.0.1:9180/apisix/admin/stream_routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"upstream": {
"type": "chash",
"key": "mqtt_client_id",
"nodes": [
{
"host": "127.0.0.1",
"port": 1995,
"weight": 1
},
{
"host": "127.0.0.2",
"port": 1995,
"weight": 1
}
]
}
}'
```
不同客户端 ID 的 MQTT 连接将通过一致性哈希算法被转发到不同的节点。如果客户端 ID 为空,将会通过客户端 IP 进行均衡。
## 使用 mqtt-proxy 插件启用 mTLS
Stream 代理可以使用 TCP 连接并且支持 TLS。请参考 [如何通过 tcp 连接接受 tls](../stream-proxy.md/#accept-tls-over-tcp-connection) 打开启用了 TLS 的 stream 代理。
`mqtt-proxy` 插件通过 Stream 代理的指定端口的 TCP 通信启用,如果 `tls` 设置为 `true`,则还要求客户端通过 TLS 进行身份验证。
配置 `ssl` 提供 CA 证书和服务器证书,以及 SNI 列表。使用 `ssl` 保护 `stream_routes` 的步骤等同于 [protect Routes](../mtls.md/#protect-route)。
### 创建 stream_route 并配置 mqtt-proxy 插件和 mTLS
通过以下示例可以创建一个配置了 `mqtt-proxy` 插件的 `stream_route`,需要提供 CA 证书、客户端证书和客户端密钥(对于不受主机信任的自签名证书,请使用 -k 选项):
```shell
curl 127.0.0.1:9180/apisix/admin/stream_routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"sni": "${your_sni_name}",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}'
```
:::note 注意
`sni` 名称必须与提供的 CA 和服务器证书创建的 SSL 对象的一个​​或多个 SNI 匹配。
:::
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/stream_routes/1 \
-H "X-API-KEY: $admin_key" -X DELETE
```

View File

@@ -0,0 +1,175 @@
---
title: multi-auth
keywords:
- Apache APISIX
- API 网关
- Plugin
- Multi Auth
- multi-auth
description: 本文档包含有关 Apache APISIX multi-auth 插件的信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
插件 `multi-auth` 用于向 `Route` 或者 `Service` 中,添加多种身份验证方式。它支持 `auth` 类型的插件。您可以使用 `multi-auth` 插件,来组合不同的身份认证方式。
插件通过迭代 `auth_plugins` 属性指定的插件列表,提供了灵活的身份认证机制。它允许多个 `Consumer` 在使用不同身份验证方式时共享相同的 `Route` ,同时。例如:一个 Consumer 使用 basic 认证,而另一个消费者使用 JWT 认证。
## 属性
For Route:
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|--------------|-------|------|-----|-------------------------|
| auth_plugins | array | True | - | 添加需要支持的认证插件。至少需要 2 个插件。 |
## 启用插件
要启用插件,您必须创建两个或多个具有不同身份验证插件配置的 Consumer
首先创建一个 Consumer 使用 basic-auth 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d '
{
"username": "foo1",
"plugins": {
"basic-auth": {
"username": "foo1",
"password": "bar1"
}
}
}'
```
然后再创建一个 Consumer 使用 key-auth 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d '
{
"username": "foo2",
"plugins": {
"key-auth": {
"key": "auth-one"
}
}
}'
```
创建 Consumer 之后,您可以配置一个路由或服务来验证请求:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {
"multi-auth":{
"auth_plugins":[
{
"basic-auth":{ }
},
{
"key-auth":{
"query":"apikey",
"hide_credentials":true,
"header":"apikey"
}
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 使用示例
如上所述配置插件后,您可以向对应的 API 发起一个请求,如下所示:
请求开启 basic-auth 插件的 API
```shell
curl -i -ufoo1:bar1 http://127.0.0.1:9080/hello
```
请求开启 key-auth 插件的 API
```shell
curl http://127.0.0.1:9080/hello -H 'apikey: auth-one' -i
```
```
HTTP/1.1 200 OK
...
hello, world
```
如果请求未授权,将会返回 `401 Unauthorized` 错误:
```json
{"message":"Authorization Failed"}
```
## 删除插件
要删除 `multi-auth` 插件,您可以从插件配置中删除插件对应的 JSON 配置APISIX 会自动加载,您不需要重新启动即可生效。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,125 @@
---
title: node-status
keywords:
- Apache APISIX
- API 网关
- 插件
- Node status
description: 本文介绍了 API 网关 Apache APISIX node-status 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`node-status` 插件可用于通过暴露的 API 查询 APISIX 的请求状态,并返回基本的状态信息。
## 插件属性
无。
## 插件接口
该插件将会增加 `/apisix/status` 的接口用来暴露 APISIX 的状态,你需要通过 [public-api](public-api.md) 插件来暴露该接口。
## 启用插件
`node-status` 插件默认为禁用状态,如果你需要使用该插件,请在配置文件 `./conf/config.yaml` 中启用它:
``` yaml title="./conf/config.yaml"
plugins:
- limit-req
- node-status
- jwt-auth
- zipkin
......
```
你需要为 `/apisix/status` API 配置路由,并使用 [public-api](public-api.md) 插件暴露它。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/ns -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/apisix/status",
"plugins": {
"public-api": {}
}
}'
```
## 测试插件
完成上述配置后,你可以通过以下命令向 `/apisix/status` 发送请求以获取状态信息。
```shell
curl http://127.0.0.1:9080/apisix/status -i
```
```shell
HTTP/1.1 200 OK
Date: Tue, 03 Nov 2020 11:12:55 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server
{"status":{"total":"23","waiting":"0","accepted":"22","writing":"1","handled":"22","active":"1","reading":"0"},"id":"6790a064-8f61-44ba-a6d3-5df42f2b1bb3"}
```
返回结果中的参数释义如下:
| 参数 | 说明 |
| ------------ | ---------------------------------------------------------------------- |
| status | APISIX 的状态信息。 |
| total | 客户端请求总数。 |
| waiting | 当前等待客户端请求的空闲连接数。 |
| accepted | 当前已经接受的客户端连接总数。 |
| writing | 当前正在写给客户端响应的连接数。 |
| handled | 当前已经处理的连接总数,除非达到其他资源的限制,否则此值与 `accepted` 相同。 |
| active | 当前活跃的客户端连接数。 |
| reading | 当前正在读取请求头的连接数。 |
| id | APISIX UID 信息,保存在 `./conf/apisix.uid` 文件中。 |
## 删除插件
如果你不再需要该插件,可以从配置文件 (`./conf/config.yaml`) 中删除它:
``` yaml title="conf/config.yaml"
- limit-req
- jwt-auth
- zipkin
......
```
你也可以移除暴露 `/apisix/status` 接口的路由。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/ns -H "X-API-KEY: $admin_key" -X DELETE
```

View File

@@ -0,0 +1,144 @@
---
title: ocsp-stapling
keywords:
- Apache APISIX
- API 网关
- 插件
- ocsp-stapling
description: 本文介绍了 API 网关 Apache APISIX ocsp-stapling 插件的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`ocsp-stapling` 插件可以动态地设置 Nginx 中 [OCSP stapling](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_stapling) 的相关行为。
## 启用插件
这个插件是默认禁用的,通过修改配置文件 `./conf/config.yaml` 来启用它:
```yaml
plugins:
- ...
- ocsp-stapling
```
修改配置文件之后,重启 APISIX 或者通过插件热加载接口来使配置生效:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugins/reload -H "X-API-KEY: $admin_key" -X PUT
```
## 属性
插件属性存储在 SSL 资源的 `ocsp_stapling` 字段中。
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|----------------|----------------------|----------|---------------|--------------|-----------------------------------------------------------------------|
| enabled | boolean | False | false | | 与 `ssl_stapling` 指令类似,用于启用或禁用 OCSP stapling 特性 |
| skip_verify | boolean | False | false | | 与 `ssl_stapling_verify` 指令类似,用于启用或禁用对于 OCSP 响应结果的校验 |
| cache_ttl | integer | False | 3600 | >= 60 | 指定 OCSP 响应结果的缓存时间 |
## 使用示例
首先您应该创建一个 SSL 资源,并且证书资源中应该包含颁发者的证书。通常情况下,全链路证书就可以正常工作。
如下示例中,生成相关的 SSL 资源:
```shell
curl http://127.0.0.1:9180/apisix/admin/ssls/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"cert" : "'"$(cat server.crt)"'",
"key": "'"$(cat server.key)"'",
"snis": ["test.com"],
"ocsp_stapling": {
"enabled": true
}
}'
```
通过上述命令生成 SSL 资源后,可以通过以下方法测试:
```shell
echo -n "Q" | openssl s_client -status -connect localhost:9443 -servername test.com 2>&1 | cat
```
```
...
CONNECTED(00000003)
OCSP response:
======================================
OCSP Response Data:
OCSP Response Status: successful (0x0)
...
```
可以通过以下方法禁用插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/ssls/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"cert" : "'"$(cat server.crt)"'",
"key": "'"$(cat server.key)"'",
"snis": ["test.com"],
"ocsp_stapling": {
"enabled": false
}
}'
```
## 删除插件
在删除插件之前,需要确保所有的 SSL 资源都已经移除 `ocsp_stapling` 字段,可以通过以下命令实现对单个 SSL 资源的对应字段移除:
```shell
curl http://127.0.0.1:9180/apisix/admin/ssls/1 \
-H "X-API-KEY: $admin_key" -X PATCH -d '
{
"ocsp_stapling": null
}'
```
通过修改配置文件 `./conf/config.yaml` 来禁用它:
```yaml
plugins:
- ...
# - ocsp-stapling
```
修改配置文件之后,重启 APISIX 或者通过插件热加载接口来使配置生效:
```shell
curl http://127.0.0.1:9180/apisix/admin/plugins/reload -H "X-API-KEY: $admin_key" -X PUT
```

View File

@@ -0,0 +1,329 @@
---
title: opa
keywords:
- Apache APISIX
- API 网关
- Plugin
- Open Policy Agent
- opa
description: 本篇文档介绍了 Apache APISIX 通过 opa 插件与 Open Policy Agent 对接的相关信息。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`opa` 插件可用于与 [Open Policy Agent](https://www.openpolicyagent.org) 进行集成,实现后端服务的认证授权与访问服务等功能解耦,减少系统复杂性。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|-------------------|---------|----------|---------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| host | string | 是 | | | OPA 服务的主机地址,例如 `https://localhost:8181`。 |
| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时,将验证 SSL 证书。 |
| policy | string | 是 | | | OPA 策略路径,是 `package``decision` 配置的组合。当使用高级功能(如自定义响应)时,你可以省略 `decision` 配置。 |
| timeout | integer | 否 | 3000ms | [1, 60000]ms | 设置 HTTP 调用超时时间。 |
| keepalive | boolean | 否 | true | | 当设置为 `true` 时,将为多个请求保持连接并处于活动状态。 |
| keepalive_timeout | integer | 否 | 60000ms | [1000, ...]ms | 连接断开后的闲置时间。 |
| keepalive_pool | integer | 否 | 5 | [1, ...]ms | 连接池限制。 |
| with_route | boolean | 否 | false | | 当设置为 `true` 时,发送关于当前 Route 的信息。 |
| with_service | boolean | 否 | false | | 当设置为 `true` 时,发送关于当前 Service 的信息。 |
| with_consumer | boolean | 否 | false | | 当设置为 `true` 时,发送关于当前 Consumer 的信息。注意,这可能会发送敏感信息,如 API key。请确保在安全的情况下才打开它。 |
## 数据定义
### APISIX 向 OPA 发送信息
下述示例代码展示了如何通过 APISIX 向 OPA 服务发送数据:
```json
{
"type": "http",
"request": {
"scheme": "http",
"path": "\/get",
"headers": {
"user-agent": "curl\/7.68.0",
"accept": "*\/*",
"host": "127.0.0.1:9080"
},
"query": {},
"port": 9080,
"method": "GET",
"host": "127.0.0.1"
},
"var": {
"timestamp": 1701234567,
"server_addr": "127.0.0.1",
"server_port": "9080",
"remote_port": "port",
"remote_addr": "ip address"
},
"route": {},
"service": {},
"consumer": {}
}
```
上述代码具体释义如下:
- `type` 代表请求类型(如 `http``stream`
- `request` 则需要在 `type``http` 时使用,包含基本的请求信息(如 URL、头信息等
- `var` 包含关于请求连接的基本信息(如 IP、端口、请求时间戳等
- `route``service``consumer` 包含的数据与 APISIX 中存储的数据相同,只有当这些对象上配置了 `opa` 插件时才会发送。
### OPA 向 APISIX 返回数据
下述示例代码展示了 OPA 服务对 APISIX 发送请求后的响应数据:
```json
{
"result": {
"allow": true,
"reason": "test",
"headers": {
"an": "header"
},
"status_code": 401
}
}
```
上述响应中的代码释义如下:
- `allow` 配置是必不可少的,它表示请求是否允许通过 APISIX 进行转发;
- `reason``headers``status_code` 是可选的,只有当你配置一个自定义响应时才会返回这些选项信息,具体使用方法可查看后续测试用例。
## 测试插件
首先启动 OPA 环境:
```shell
docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s
```
### 基本用法
一旦你运行了 OPA 服务,就可以进行基本策略的创建:
```shell
curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
-H 'Content-Type: text/plain' \
-d 'package example1
import input.request
default allow = false
allow {
# HTTP method must GET
request.method == "GET"
}'
```
然后在指定路由上配置 `opa` 插件:
```shell
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \
-H 'X-API-KEY: <api-key>' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/*",
"plugins": {
"opa": {
"host": "http://127.0.0.1:8181",
"policy": "example1"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
使用如下命令进行测试:
```shell
curl -i -X GET 127.0.0.1:9080/get
```
```shell
HTTP/1.1 200 OK
```
如果尝试向不同的端点发出请求,会出现请求失败的状态:
```shell
curl -i -X POST 127.0.0.1:9080/post
```
```shell
HTTP/1.1 403 FORBIDDEN
```
### 使用自定义响应
除了基础用法外,你还可以为更复杂的使用场景配置自定义响应,参考示例如下:
```shell
curl -X PUT '127.0.0.1:8181/v1/policies/example2' \
-H 'Content-Type: text/plain' \
-d 'package example2
import input.request
default allow = false
allow {
request.method == "GET"
}
# custom response body (Accepts a string or an object, the object will respond as JSON format)
reason = "test" {
not allow
}
# custom response header (The data of the object can be written in this way)
headers = {
"Location": "http://example.com/auth"
} {
not allow
}
# custom response status code
status_code = 302 {
not allow
}'
```
同时,你可以将 `opa` 插件的策略参数调整为 `example2`,然后发出请求进行测试:
```shell
curl -i -X GET 127.0.0.1:9080/get
```
```shell
HTTP/1.1 200 OK
```
此时如果你发出一个失败请求,将会收到来自 OPA 服务的自定义响应反馈,如下所示:
```shell
curl -i -X POST 127.0.0.1:9080/post
```
```shell
HTTP/1.1 302 FOUND
Location: http://example.com/auth
test
```
### 发送 APISIX 数据
如果你的 OPA 服务需要根据 APISIX 的某些数据(如 Route 和 Consumer 的详细信息)来进行后续操作时,则可以通过配置插件来实现。
下述示例展示了一个简单的 `echo` 策略,它将原样返回 APISIX 发送的数据:
```shell
curl -X PUT '127.0.0.1:8181/v1/policies/echo' \
-H 'Content-Type: text/plain' \
-d 'package echo
allow = false
reason = input'
```
现在就可以在路由上配置插件来发送 APISIX 数据:
```shell
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \
-H 'X-API-KEY: <api-key>' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/*",
"plugins": {
"opa": {
"host": "http://127.0.0.1:8181",
"policy": "echo",
"with_route": true
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
此时如果你提出一个请求,则可以通过自定义响应看到来自路由的数据:
```shell
curl -X GET 127.0.0.1:9080/get
```
```shell
{
"type": "http",
"request": {
xxx
},
"var": {
xxx
},
"route": {
xxx
}
}
```
## 删除插件
当你需要禁用 `opa` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,171 @@
---
title: openfunction
keywords:
- Apache APISIX
- API 网关
- Plugin
- OpenFunction
description: 本文介绍了 API 网关 Apache APISIX 的 openfunction 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`openfunction` 插件用于将开源的分布式无服务器平台 [CNCF OpenFunction](https://openfunction.dev/) 作为动态上游集成至 APISIX。
启用 `openfunction` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 OpenFunction 的 function 发起一个新的请求,然后 `openfunction` 插件会将响应信息返回至客户端。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------------------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ |
| function_uri | string | 是 | | | OpenFunction function uri例如 `https://localhost:30858/default/function-sample`。 |
| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 |
| authorization | object | 否 | | | 访问 OpenFunction 的函数的授权凭证。|
| authorization.service_token | string | 否 | | | OpenFunction service token其格式为 `xxx:xxx`,支持函数入口的 basic auth 认证方式。 |
| timeout | integer | 否 | 3000 ms | [100,...] ms | OpenFunction action 和 HTTP 调用超时时间,以毫秒为单位。 |
| keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 |
| keepalive_timeout | integer | 否 | 60000 ms| [1000,...] ms| 当连接空闲时,保持该连接处于活动状态的时间,以毫秒为单位。 |
| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 |
:::note 注意
`timeout` 字段规定了 OpenFunction function 的最大执行时间,以及 APISIX 中 HTTP 客户端的请求超时时间。
因为 OpenFunction function 调用可能会耗费很长时间来拉取容器镜像和启动容器,如果 `timeout` 字段的值设置太小,可能会导致大量请求失败。
:::
## 前提条件
在使用 `openfunction` 插件之前,你需要通过以下命令运行 OpenFunction。详情参考 [OpenFunction 安装指南](https://openfunction.dev/docs/getting-started/installation/)
请确保当前环境中已经安装对应版本的 Kubernetes 集群。
### 创建并推送函数
你可以参考 [OpenFunction 官方示例](https://github.com/OpenFunction/samples) 创建函数。构建函数时,你需要使用以下命令为容器仓库生成一个密钥,才可以将函数容器镜像推送到容器仓库 ( 例如 Docker Hub 或 Quay.io
```shell
REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=<your_registry_user> REGISTRY_PASSWORD=<your_registry_password>
kubectl create secret docker-registry push-secret \
--docker-server=$REGISTRY_SERVER \
--docker-username=$REGISTRY_USER \
--docker-password=$REGISTRY_PASSWORD
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {
"openfunction": {
"function_uri": "http://localhost:3233/default/function-sample/test",
"authorization": {
"service_token": "test:test"
}
}
}
}'
```
## 测试插件
使用 `curl` 命令测试:
```shell
curl -i http://127.0.0.1:9080/hello -X POST -d'test'
```
正常返回结果:
```
hello, test!
```
### 配置路径转发
`OpenFunction` 插件还支持 URL 路径转发,同时将请求代理到上游的 OpenFunction API 端点。基本请求路径的扩展(如路由 `/hello/*``*` 的部分)会被添加到插件配置中指定的 `function_uri`
:::info 重要
路由上配置的 `uri` 必须以 `*` 结尾此功能才能正常工作。APISIX 路由是严格匹配的,`*` 表示此 URI 的任何子路径都将匹配到同一路由。
:::
下面的示例配置了此功能:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello/*",
"plugins": {
"openfunction": {
"function_uri": "http://localhost:3233/default/function-sample",
"authorization": {
"service_token": "test:test"
}
}
}
}'
```
现在,对路径 `hello/123` 的任何请求都将调用 OpenFunction 插件设置的对应的函数,并转发添加的路径:
```shell
curl http://127.0.0.1:9080/hello/123
```
```shell
Hello, 123!
```
## 删除插件
当你需要禁用 `openfunction` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,257 @@
---
title: openid-connect
keywords:
- Apache APISIX
- API 网关
- OpenID Connect
- OIDC
description: openid-connect 插件支持与 OpenID Connect (OIDC) 身份提供商集成,例如 Keycloak、Auth0、Microsoft Entra ID、Google、Okta 等。它允许 APISIX 对客户端进行身份验证并从身份提供商处获取其信息,然后允许或拒绝其访问上游受保护资源。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/openid-connect" />
</head>
## 描述
`openid-connect` 插件支持与 [OpenID Connect (OIDC)](https://openid.net/connect/) 身份提供商集成,例如 Keycloak、Auth0、Microsoft Entra ID、Google、Okta 等。它允许 APISIX 对客户端进行身份验证,并从身份提供商处获取其信息,然后允许或拒绝其访问上游受保护资源。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------------------------ | ------- | ------ | --------------------- | ------------- | ------------------------------------------------------------------------------------------------ |
| client_id | string | 是 | | | OAuth 客户端 ID。 |
| client_secret | string | 是 | | | OAuth 客户端 secret。 |
| discovery | string | 是 | | | OpenID 提供商的知名发现文档的 URL其中包含 OP API 端点列表。插件可以直接利用发现文档中的端点。您也可以单独配置这些端点,这优先于发现文档中提供的端点。 |
| scope | string | 否 | openid | | 与应返回的有关经过身份验证的用户的信息相对应的 OIDC 范围,也称为 [claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)。这用于向用户授权适当的权限。默认值为 `openid`,这是 OIDC 返回唯一标识经过身份验证的用户的 `sub` 声明所需的范围。可以附加其他范围并用空格分隔,例如 `openid email profile`。 |
| required_scopes | array[string] | 否 | | | 访问令牌中必须存在的范围。当 `bearer_only``true` 时与自省端点结合使用。如果缺少任何必需的范围,插件将以 403 禁止错误拒绝请求。|
| realm | string | 否 | apisix | | 由于持有者令牌无效,[`WWW-Authenticate`](https://www.rfc-editor.org/rfc/rfc6750#section-3) 响应标头中的领域伴随 401 未经授权的请求。 |
| bearer_only | boolean | 否 | false | | 如果为 true则严格要求在身份验证请求中使用持有者访问令牌。 |
| logout_path | string | 否 | /logout | | 激活注销的路径。 |
| post_logout_redirect_uri | string | 否 | | | `logout_path` 收到注销请求后将用户重定向到的 URL。|
| redirect_uri | string | 否 | | | 通过 OpenID 提供商进行身份验证后重定向到的 URI。请注意重定向 URI 不应与请求 URI 相同,而应为请求 URI 的子路径。例如,如果路由的 `uri``/api/v1/*`,则 `redirect_uri` 可以配置为 `/api/v1/redirect`。如果未配置 `redirect_uri`APISIX 将在请求 URI 后附加 `/.apisix/redirect` 以确定 `redirect_uri` 的值。|
| timeout | integer | 否 | 3 | [1,...] | 请求超时时间(秒)。|
| ssl_verify | boolean | 否 | false | | 如果为 true则验证 OpenID 提供商的 SSL 证书。|
| introspection_endpoint | string | 否 | | |用于自检访问令牌的 OpenID 提供程序的 [令牌自检](https://datatracker.ietf.org/doc/html/rfc7662) 端点的 URL。如果未设置则将使用众所周知的发现文档中提供的自检端点[作为后备](https://github.com/zmartzone/lua-resty-openidc/commit/cdaf824996d2b499de4c72852c91733872137c9c)。|
| introspection_endpoint_auth_method | string | 否 | client_secret_basic | | 令牌自检端点的身份验证方法。该值应为 `introspection_endpoint_auth_methods_supported` [授权服务器元数据](https://www.rfc-editor.org/rfc/rfc8414.html) 中指定的身份验证方法之一,如众所周知的发现文档中所示,例如 `client_secret_basic``client_secret_post``private_key_jwt``client_secret_jwt`。|
| token_endpoint_auth_method | string | 否 | client_secret_basic | | 令牌端点的身份验证方法。该值应为 `token_endpoint_auth_methods_supported` [授权服务器元数据](https://www.rfc-editor.org/rfc/rfc8414.html) 中指定的身份验证方法之一,如众所周知的发现文档中所示,例如 `client_secret_basic``client_secret_post``private_key_jwt``client_secret_jwt`。如果配置的方法不受支持,则回退到 `token_endpoint_auth_methods_supported` 数组中的第一个方法。|
| public_key | string | 否 | | | 用于验证 JWT 签名 id 的公钥使用非对称算法。提供此值来执行令牌验证将跳过客户端凭据流中的令牌自检。您可以以 `-----BEGIN PUBLIC KEY-----\\n……\\n-----END PUBLIC KEY-----` 格式传递公钥。|
| use_jwks | boolean | 否 | false | | 如果为 true 并且未设置 `public_key`,则使用 JWKS 验证 JWT 签名并跳过客户端凭据流中的令牌自检。JWKS 端点是从发现文档中解析出来的。|
| use_pkce | boolean | 否 | false | | 如果为 true则使用 [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) 中定义的授权码流的代码交换证明密钥 (PKCE)。|
| token_signing_alg_values_expected | string | 否 | | | 用于签署 JWT 的算法,例如 `RS256`。 |
| set_access_token_header | boolean | 否 | true | | 如果为 true则在请求标头中设置访问令牌。默认情况下使用 `X-Access-Token` 标头。|
| access_token_in_authorization_header | boolean | 否 | false | | 如果为 true 并且 `set_access_token_header` 也为 true则在 `Authorization` 标头中设置访问令牌。 |
| set_id_token_header | boolean | 否 | true | | 如果为 true 并且 ID 令牌可用,则在 `X-ID-Token` 请求标头中设置值。 |
| set_userinfo_header | boolean | 否 | true | | 如果为 true 并且用户信息数据可用,则在 `X-Userinfo` 请求标头中设置值。 |
| set_refresh_token_header | boolean | 否 | false | | 如果为 true 并且刷新令牌可用,则在 `X-Refresh-Token` 请求标头中设置值。 |
| session | object | 否 | | | 当 `bearer_only``false` 且插件使用 Authorization Code 流程时使用的 Session 配置。 |
| session.secret | string | 是 | | 16 个字符以上 | 当 `bearer_only``false` 时,用于 session 加密和 HMAC 运算的密钥,若未配置则自动生成并保存到 etcd。当在独立模式下使用 APISIX 时etcd 不再是配置中心,需要配置 `secret`。 |
| session.cookie | object | 否 | | | Cookie 配置。 |
| session.cookie.lifetime | integer | 否 | 3600 | | Cookie 生存时间(秒)。|
| unauth_action | string | 否 | auth | ["auth","deny","pass"] | 未经身份验证的请求的操作。设置为 `auth` 时,重定向到 OpenID 提供程序的身份验证端点。设置为 `pass` 时,允许请求而无需身份验证。设置为 `deny` 时,返回 401 未经身份验证的响应,而不是启动授权代码授予流程。|
| session_contents | object | 否 | | | 会话内容配置。如果未配置,将把所有数据存储在会话中。 |
| session_contents.access_token | boolean | 否 | | | 若为 true则将访问令牌存储在会话中。 |
| session_contents.id_token | boolean | 否 | | | 若为 true则将 ID 令牌存储在会话中。 |
| session_contents.enc_id_token | boolean | 否 | | | 若为 true则将加密的 ID 令牌存储在会话中。 |
| session_contents.user | boolean | 否 | | | 若为 true则将用户信息存储在会话中。 |
| proxy_opts | object | 否 | | | OpenID 提供程序背后的代理服务器的配置。|
| proxy_opts.http_proxy | string | 否 | | | HTTP 请求的代理服务器地址,例如 `http://<proxy_host>:<proxy_port>`。|
| proxy_opts.https_proxy | string | 否 | | | HTTPS 请求的代理服务器地址,例如 `http://<proxy_host>:<proxy_port>`。 |
| proxy_opts.http_proxy_authorization | string | 否 | | Basic [base64 用户名:密码] | 与 `http_proxy` 一起使用的默认 `Proxy-Authorization` 标头值。可以用自定义的 `Proxy-Authorization` 请求标头覆盖。 |
| proxy_opts.https_proxy_authorization | string | 否 | | Basic [base64 用户名:密码] | 与 `https_proxy` 一起使用的默认 `Proxy-Authorization` 标头值。不能用自定义的 `Proxy-Authorization` 请求标头覆盖,因为使用 HTTPS 时,授权在连接时完成。 |
| proxy_opts.no_proxy | string | 否 | | | 不应代理的主机的逗号分隔列表。|
| authorization_params | object | 否 | | | 在请求中发送到授权端点的附加参数。 |
| client_rsa_private_key | string | 否 | | | 用于签署 JWT 以向 OP 进行身份验证的客户端 RSA 私钥。当 `token_endpoint_auth_method``private_key_jwt` 时必需。 |
| client_rsa_private_key_id | string | 否 | | | 用于计算签名的 JWT 的客户端 RSA 私钥 ID。当 `token_endpoint_auth_method``private_key_jwt` 时可选。 |
| client_jwt_assertion_expires_in | integer | 否 | 60 | | 用于向 OP 进行身份验证的签名 JWT 的生命周期,以秒为单位。当 `token_endpoint_auth_method``private_key_jwt``client_secret_jwt` 时使用。 |
| renew_access_token_on_expiry | boolean | 否 | true | | 如果为 true则在访问令牌过期或刷新令牌可用时尝试静默更新访问令牌。如果令牌无法更新则重定向用户进行重新身份验证。|
| access_token_expires_in | integer | 否 | | | 如果令牌端点响应中不存在 `expires_in` 属性,则访问令牌的有效期(以秒为单位)。 |
| refresh_session_interval | integer | 否 | | | 刷新用户 ID 令牌而无需重新认证的时间间隔。如果未设置,则不会检查网关向客户端发出的会话的到期时间。如果设置为 900则表示在 900 秒后刷新用户的 `id_token`(或浏览器中的会话),而无需重新认证。 |
| iat_slack | integer | 否 | 120 | | ID 令牌中 `iat` 声明的时钟偏差容忍度(以秒为单位)。 |
| accept_none_alg | boolean | 否 | false | | 如果 OpenID 提供程序未签署其 ID 令牌(例如当签名算法设置为`none` 时),则设置为 true。 |
| accept_unsupported_alg | boolean | 否 | true | | 如果为 true则忽略 ID 令牌签名以接受不支持的签名算法。 |
| access_token_expires_leeway | integer | 否 | 0 | | 访问令牌续订的过期余地(以秒为单位)。当设置为大于 0 的值时,令牌续订将在令牌过期前设定的时间内进行。这样可以避免访问令牌在到达资源服务器时刚好过期而导致的错误。|
| force_reauthorize | boolean | 否 | false | | 如果为 true即使令牌已被缓存也执行授权流程。 |
| use_nonce | boolean | 否 | false | | 如果为 true在授权请求中启用 nonce 参数。 |
| revoke_tokens_on_logout | boolean | 否 | false | | 如果为 true则通知授权服务器撤销端点不再需要先前获得的刷新或访问令牌。 |
| jwk_expires_in | integer | 否 | 86400 | | JWK 缓存的过期时间(秒)。 |
| jwt_verification_cache_ignore | boolean | 否 | false | | 如果为 true则强制重新验证承载令牌并忽略任何现有的缓存验证结果。 |
| cache_segment | string | 否 | | | 缓存段的可选名称,用于分隔和区分令牌自检或 JWT 验证使用的缓存。|
| introspection_interval | integer | 否 | 0 | | 缓存和自省访问令牌的 TTL以秒为单位。默认值为 0这意味着不使用此选项插件默认使用 `introspection_expiry_claim` 中定义的到期声明传递的 TTL。如果`introspection_interval` 大于 0 且小于 `introspection_expiry_claim` 中定义的到期声明传递的 TTL则使用`introspection_interval`。|
| introspection_expiry_claim | string | 否 | exp | | 到期声明的名称,它控制缓存和自省访问令牌的 TTL。|
| introspection_addon_headers | array[string] | 否 | | | 用于将其他标头值附加到自省 HTTP 请求。如果原始请求中不存在指定的标头,则不会附加值。|
| claim_validator.issuer.valid_issuers | string[] | 否 | | | 将经过审查的 jwt 发行者列入白名单。当用户未传递时,将使用发现端点返回的颁发者。如果两者均缺失,发行人将无法得到验证|
注意schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
## 示例
以下示例演示了如何针对不同场景配置 `openid-connect` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### Authorization Code Flow
Authorization Code Flow 在 [RFC 6749第 4.1 节](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1) 中定义。它涉及用临时授权码交换访问令牌,通常由机密和公共客户端使用。
下图说明了实施 Authorization Code Flow 时不同实体之间的交互:
![授权码流程图](https://static.api7.ai/uploads/2023/11/27/Ga2402sb_oidc-code-auth-flow-revised.png)
当传入请求的标头中或适当的会话 cookie 中不包含访问令牌时,插件将充当依赖方并重定向到授权服务器以继续授权码流程。
成功验证后,插件将令牌保留在会话 cookie 中,后续请求将使用存储在 cookie 中的令牌。
请参阅 [实现 Authorization Code Flow](../tutorials/keycloak-oidc.md#实现-authorization-code-grant)以获取使用`openid-connect`插件通过授权码流与 Keycloak 集成的示例。
### Proof Key for Code Exchange (PKCE)
Proof Key for Code Exchange (PKCE) 在 [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) 中定义。PKCE 通过添加代码质询和验证器来增强授权码流程,以防止授权码拦截攻击。
下图说明了使用 PKCE 实现授权码流程时不同实体之间的交互:
![使用 PKCE 的授权码流程图](https://static.api7.ai/uploads/2024/11/04/aJ2ZVuTC_auth-code-with-pkce.png)
请参阅 [实现 Authorization Code Grant](../tutorials/keycloak-oidc.md#实现-authorization-code-grant),了解使用 `openid-connect` 插件通过 PKCE 授权码流程与 Keycloak 集成的示例。
### Client Credential Flow
Client Credential Flow 在 [RFC 6749第 4.4 节](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4) 中定义。它涉及客户端使用自己的凭证请求访问令牌以访问受保护的资源,通常用于机器对机器身份验证,并不代表特定用户。
下图说明了实施 Client Credential Flow 时不同实体之间的交互:
<div style={{textAlign: 'center'}}>
<img src="https://static.api7.ai/uploads/2024/10/28/sbHxqnOz_client-credential-no-introspect.png" alt="Client credential flow diagram" style={{width: '70%'}} />
</div>
<br />
请参阅[实现 Client Credentials Grant](../tutorials/keycloak-oidc.md#实现-client-credentials-grant) 获取使用 `openid-connect` 插件通过客户端凭证流与 Keycloak 集成的示例。
### Introspection Flow
Introspection Flow 在 [RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662) 中定义。它涉及通过查询授权服务器的自省端点来验证访问令牌的有效性和详细信息。
在此流程中,当客户端向资源服务器出示访问令牌时,资源服务器会向授权服务器的自省端点发送请求,如果令牌处于活动状态,则该端点会响应令牌详细信息,包括令牌到期时间、相关范围以及它所属的用户或客户端等信息。
下图说明了使用令牌自省实现 Introspection Flow 时不同实体之间的交互:
<br />
<div style={{textAlign: 'center'}}>
<img src="https://static.api7.ai/uploads/2024/10/29/Y2RWIUV9_client-cred-flow-introspection.png" alt="Client credential with introspection diagram" style={{width: '55%'}} />
</div>
<br />
请参阅 [实现 Client Credentials Grant](../tutorials/keycloak-oidc.md#实现-client-credentials-grant) 以获取使用 `openid-connect` 插件通过带有令牌自省的客户端凭据流与 Keycloak 集成的示例。
### Password Flow
Password Flow 在 [RFC 6749第 4.3 节](https://datatracker.ietf.org/doc/html/rfc6749#section-4.3) 中定义。它专为受信任的应用程序而设计,允许它们使用用户的用户名和密码直接获取访问令牌。在此授权类型中,客户端应用程序将用户的凭据连同其自己的客户端 ID 和密钥一起发送到授权服务器,然后授权服务器对用户进行身份验证,如果有效,则颁发访问令牌。
虽然高效,但此流程仅适用于高度受信任的第一方应用程序,因为它要求应用程序直接处理敏感的用户凭据,如果在第三方环境中使用,则会带来重大安全风险。
下图说明了实施 Password Flow 时不同实体之间的交互:
<div style={{textAlign: 'center'}}>
<img src="https://static.api7.ai/uploads/2024/10/30/njkWZVgX_pass-grant.png" alt="Password flow diagram" style={{width: '70%'}} />
</div>
<br />
请参阅 [实现 Password Grant](../tutorials/keycloak-oidc.md#实现-password-grant) 获取使用 `openid-connect` 插件通过密码流与 Keycloak 集成的示例。
### Refresh Token Grant
Refresh Token Grant 在 [RFC 6749第 6 节](https://datatracker.ietf.org/doc/html/rfc6749#section-6) 中定义。它允许客户端使用之前颁发的刷新令牌请求新的访问令牌,而无需用户重新进行身份验证。此流程通常在访问令牌过期时使用,允许客户端无需用户干预即可持续访问资源。刷新令牌与某些 OAuth 流程中的访问令牌一起颁发,其使用寿命和安全要求取决于授权服务器的配置。
下图说明了在实施 Password Grant 和 Refresh Token Grant 时不同实体之间的交互:
<div style={{textAlign: 'center'}}>
<img src="https://static.api7.ai/uploads/2024/10/30/YBF7rI6M_password-with-refresh-token.png" alt="Password grant with refresh token flow diagram" style={{width: '100%'}} />
</div>
<br />
请参阅 [Refresh Token](../tutorials/keycloak-oidc.md#refresh-token) 获取使用 `openid-connect` 插件通过带令牌刷新的密码流与 Keycloak 集成的示例。
## 故障排除
本节介绍使用此插件时的一些常见问题,以帮助您排除故障。
### APISIX 无法连接到 OpenID 提供商
如果 APISIX 无法解析或无法连接到 OpenID 提供商,请仔细检查配置文件 `config.yaml` 中的 DNS 设置并根据需要进行修改。
### `No Session State Found`
如果您在使用[授权码流](#authorization-code-flow) 时遇到 500 内部服务器错误并在日志中显示以下消息,则可能有多种原因。
```text
the error request to the redirect_uri path, but there's no session state found
```
#### 1. 重定向 URI 配置错误
一个常见的错误配置是将 `redirect_uri` 配置为与路由的 URI 相同。当用户发起访问受保护资源的请求时,请求直接命中重定向 URI且请求中没有 session cookie从而导致 no session state found 错误。
要正确配置重定向 URI请确保 `redirect_uri` 与配置插件的路由匹配,但不要完全相同。例如,正确的配置是将路由的 `uri` 配置为 `/api/v1/*`,并将 `redirect_uri` 的路径部分配置为 `/api/v1/redirect`
您还应该确保 `redirect_uri` 包含 scheme例如 `http``https`
#### 2. 缺少 Session Secret
如果您在[standalone 模式](../../../en/latest/deployment-modes.md#standalone)下部署 APISIX请确保配置了 `session.secret`
用户 session 作为 cookie 存储在浏览器中,并使用 session 密钥进行加密。如果没有通过 `session.secret` 属性配置机密,则会自动生成机密并将其保存到 etcd。然而在独立模式下etcd 不再是配置中心。因此,您应该在 YAML 配置中心 `apisix.yaml` 中为此插件显式配置 `session.secret`
#### 3. Cookie 未发送或不存在
检查 [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) cookie 属性是否已正确设置(即您的应用程序是否需要跨站点发送 cookie看看这是否会成为阻止 cookie 保存到浏览器的 cookie jar 或从浏览器发送的因素。
#### 4. 上游发送的标头太大
如果您有 NGINX 位于 APISIX 前面来代理客户端流量,请查看 NGINX 的 `error.log` 中是否观察到以下错误:
```text
upstream sent too big header while reading response header from upstream
```
如果是这样,请尝试将 `proxy_buffers``proxy_buffer_size``proxy_busy_buffers_size` 调整为更大的值。
另一个选项是配置 `session_content` 属性来调整在会话中存储哪些数据。例如,你可以将 `session_content.access_token` 设置为 `true`
#### 5. 无效的客户端密钥
验证 `client_secret` 是否有效且正确。无效的 `client_secret` 将导致身份验证失败,并且不会返回任何令牌并将其存储在 session 中。
#### 6. PKCE IdP 配置
如果您使用授权码流程启用 PKCE请确保您已将 IdP 客户端配置为使用 PKCE。例如在 Keycloak 中,您应该在客户端的高级设置中配置 PKCE 质询方法:
<div style={{textAlign: 'center'}}>
<img src="https://static.api7.ai/uploads/2024/11/04/xvnCNb20_pkce-keycloak-revised.jpeg" alt="PKCE keycloak configuration" style={{width: '70%'}} />
</div>

View File

@@ -0,0 +1,217 @@
---
title: opentelemetry
keywords:
- Apache APISIX
- API 网关
- Plugin
- OpenTelemetry
description: opentelemetry 插件可用于根据 OpenTelemetry 协议规范上报 Traces 数据,该插件仅支持二进制编码的 OLTP over HTTP。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/opentelemetry" />
</head>
## 描述
`opentelemetry` 插件可用于根据 [OpenTelemetry Specification](https://opentelemetry.io/docs/reference/specification/) 协议规范上报 Traces 数据。该插件仅支持二进制编码的 OLTP over HTTP即请求类型为 `application/x-protobuf` 的数据上报。
## 配置
默认情况下,服务名称、租户 ID、collector 和 batch span processor 的配置已预配置在[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中。
您可以通过端点 `apisix/admin/plugin_metadata/opentelemetry` 更改插件的配置,例如:
:::note
您可以从“config.yaml”获取“admin_key”,并使用以下命令保存到环境变量中:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/opentelemetry -H "X-API-KEY: $admin_key" -X PUT -d '
{
"trace_id_source": "x-request-id",
"resource": {
"service.name": "APISIX"
},
"collector": {
"address": "127.0.0.1:4318",
"request_timeout": 3,
"request_headers": {
"Authorization": "token"
}
},
"batch_span_processor": {
"drop_on_queue_full": false,
"max_queue_size": 1024,
"batch_timeout": 2,
"inactive_timeout": 1,
"max_export_batch_size": 16
},
"set_ngx_var": false
}'
```
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|---------------------------------------|---------------|----------|--------------|--------------|-------------|
| sampler | object | 否 | - | - | 采样策略。 |
| sampler.name | string | 否 | `always_off` | ["always_on", "always_off", "trace_id_ratio", "parent_base"] | 采样策略。<br />`always_on`:全采样;`always_off`:不采样;`trace_id_ratio`:基于 trace id 的百分比采样;`parent_base`:如果存在 tracing 上游,则使用上游的采样决定,否则使用配置的采样策略决策。|
| sampler.options | object | 否 | - | - | 采样策略参数。 |
| sampler.options.fraction | number | 否 | 0 | [0, 1] | `trace_id_ratio`:采样策略的百分比。 |
| sampler.options.root | object | 否 | - | - | `parent_base`:采样策略在没有上游 tracing 时,会使用 root 采样策略做决策。|
| sampler.options.root.name | string | 否 | - | ["always_on", "always_off", "trace_id_ratio"] | root 采样策略。 |
| sampler.options.root.options | object | 否 | - | - | root 采样策略参数。 |
| sampler.options.root.options.fraction | number | 否 | 0 | [0, 1] | `trace_id_ratio` root 采样策略的百分比|
| additional_attributes | array[string] | 否 | - | - | 追加到 trace span 的额外属性,支持内置 NGINX 或 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)。|
| additional_header_prefix_attributes | array[string] | 否 | - | - | 附加到跟踪范围属性的标头或标头前缀。例如,使用 `x-my-header"``x-my-headers-*` 来包含带有前缀 `x-my-headers-` 的所有标头。 |
## 示例
以下示例展示了如何在不同场景下使用 `opentelemetry` 插件。
### 启用 opentelemetry 插件
默认情况下APISIX 中的 `opentelemetry` 插件是禁用的。要启用它,请将插件添加到配置文件中,如下所示:
```yaml title="config.yaml"
plugins:
- ...
- opentelemetry
```
重新加载 APISIX 以使更改生效。
有关 `config.yaml` 中可以配置的其他选项,请参阅[静态配置](#静态配置)。
### 将 Traces 上报到 OpenTelemetry
以下示例展示了如何追踪对路由的请求并将 traces 发送到 OpenTelemetry。
在 Docker 启动一个 OpenTelemetry collector 实例:
```shell
docker run -d --name otel-collector -p 4318:4318 otel/opentelemetry-collector-contrib
```
创建一个开启了 `opentelemetry` 插件的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "otel-tracing-route",
"uri": "/anything",
"plugins": {
"opentelemetry": {
"sampler": {
"name": "always_on"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送请求:
```shell
curl "http://127.0.0.1:9080/anything"
```
你应该收到一个 `HTTP/1.1 200 OK` 响应。
在 OpenTelemetry collector 的日志中,你应该看到类似以下的信息:
```text
2024-02-18T17:14:03.825Z info ResourceSpans #0
Resource SchemaURL:
Resource attributes:
-> telemetry.sdk.language: Str(lua)
-> telemetry.sdk.name: Str(opentelemetry-lua)
-> telemetry.sdk.version: Str(0.1.1)
-> hostname: Str(e34673e24631)
-> service.name: Str(APISIX)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope opentelemetry-lua
Span #0
Trace ID : fbd0a38d4ea4a128ff1a688197bc58b0
Parent ID :
ID : af3dc7642104748a
Name : GET /anything
Kind : Server
Start time : 2024-02-18 17:14:03.763244032 +0000 UTC
End time : 2024-02-18 17:14:03.920229888 +0000 UTC
Status code : Unset
Status message :
Attributes:
-> net.host.name: Str(127.0.0.1)
-> http.method: Str(GET)
-> http.scheme: Str(http)
-> http.target: Str(/anything)
-> http.user_agent: Str(curl/7.64.1)
-> apisix.route_id: Str(otel-tracing-route)
-> apisix.route_name: Empty()
-> http.route: Str(/anything)
-> http.status_code: Int(200)
{"kind": "exporter", "data_type": "traces", "name": "debug"}
```
要可视化这些追踪,你可以将 traces 导出到后端服务,例如 Zipkin 和 Prometheus。有关更多详细信息请参阅[exporters](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter)。
### 在日志中使用 trace 变量
以下示例展示了如何配置 `opentelemetry` 插件以设置以下内置变量,这些变量可以在日志插件或访问日志中使用:
- `opentelemetry_context_traceparent`: [W3C trace context](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format)
- `opentelemetry_trace_id`: 当前 span 的 trace_id
- `opentelemetry_span_id`: 当前 span 的 span_id
如下更新配置文件。你应该自定义访问日志格式以使用 `opentelemetry` 插件变量,并在 `set_ngx_var` 字段中设置 `opentelemetry` 变量。
```yaml title="conf/config.yaml"
nginx_config:
http:
enable_access_log: true
access_log_format: '{"time": "$time_iso8601","opentelemetry_context_traceparent": "$opentelemetry_context_traceparent","opentelemetry_trace_id": "$opentelemetry_trace_id","opentelemetry_span_id": "$opentelemetry_span_id","remote_addr": "$remote_addr"}'
access_log_format_escape: json
plugin_attr:
opentelemetry:
set_ngx_var: true
```
重新加载 APISIX 以使配置更改生效。
```text
{"time": "18/Feb/2024:15:09:00 +0000","opentelemetry_context_traceparent": "00-fbd0a38d4ea4a128ff1a688197bc58b0-8f4b9d9970a02629-01","opentelemetry_trace_id": "fbd0a38d4ea4a128ff1a688197bc58b0","opentelemetry_span_id": "af3dc7642104748a","remote_addr": "172.10.0.1"}
```

View File

@@ -0,0 +1,148 @@
---
title: openwhisk
keywords:
- Apache APISIX
- API 网关
- Plugin
- OpenWhisk
description: 本文介绍了关于 Apache APISIX openwhisk 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`openwhisk` 插件用于将开源的分布式无服务器平台 [Apache OpenWhisk](https://openwhisk.apache.org) 作为动态上游集成至 APISIX。
启用 `openwhisk` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 OpenWhisk 的 API Host 端点发起一个新的请求,然后 `openwhisk` 插件会将响应信息返回至客户端。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ |
| api_host | string | 是 | | | OpenWhisk API Host 地址,例如 `https://localhost:3233`。 |
| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 |
| service_token | string | 是 | | | OpenWhisk service token其格式为 `xxx:xxx` ,用于 API 调用时的身份认证。 |
| namespace | string | 是 | | | OpenWhisk namespace例如 `guest`。 |
| action | string | 是 | | | OpenWhisk action例如 `hello`。 |
| result | boolean | 否 | true | | 当设置为 `true` 时,获得 action 元数据(执行函数并获得响应结果)。 |
| timeout | integer | 否 | 60000ms | [1,60000]ms | OpenWhisk action 和 HTTP 调用超时时间(以毫秒为单位)。 |
| keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 |
| keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 |
| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 |
:::note 注意
`timeout` 字段规定了 OpenWhisk action 的最大执行时间,以及 APISIX 中 HTTP 客户端的请求超时时间。
因为 OpenWhisk action 调用可能会耗费很长时间来拉取容器镜像和启动容器,所以如果 `timeout` 字段值设置太小,可能会导致大量的失败请求。
在 OpenWhisk 中 `timeout` 字段的值设置范围从 1 ms 到 60000 ms建议用户将 `timeout` 字段的值至少设置为 1000ms。
:::
## 启用插件
### 搭建 Apache OpenWhisk 测试环境
1. 在使用 `openwhisk` 插件之前,你需要通过以下命令运行 OpenWhisk standalone 模式。请确保当前环境中已经安装 Docker 软件。
```shell
docker run --rm -d \
-h openwhisk --name openwhisk \
-p 3233:3233 -p 3232:3232 \
-v /var/run/docker.sock:/var/run/docker.sock \
openwhisk/standalone:nightly
docker exec openwhisk waitready
```
2. 安装 [openwhisk-cli](https://github.com/apache/openwhisk-cli) 工具:
你可以在 [openwhisk-cli](https://github.com/apache/openwhisk-cli) 仓库下载已发布的适用于 Linux 系统的可执行二进制文件 wsk。
3. 在 OpenWhisk 中注册函数:
```shell
wsk property set --apihost "http://localhost:3233" --auth "${service_token}"
wsk action update test <(echo 'function main(){return {"ready":true}}') --kind nodejs:14
```
### 创建路由
你可以通过以下命令在指定路由中启用该插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {
"openwhisk": {
"api_host": "http://localhost:3233",
"service_token": "${service_token}",
"namespace": "guest",
"action": "test"
}
}
}'
```
### 测试请求
使用 `curl` 命令测试:
```shell
curl -i http://127.0.0.1:9080/hello
```
正常返回结果:
```json
{ "ready": true }
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,474 @@
---
title: prometheus
keywords:
- Apache APISIX
- API 网关
- Plugin
- Prometheus
description: 本文将介绍 prometheus 插件,以及将 APISIX 与 Prometheus 集成以进行指标收集和持续监控。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/prometheus" />
</head>
## 描述
`prometheus` 插件提供将 APISIX 与 Prometheus 集成的能力。
启用该插件后APISIX 将开始收集相关指标,例如 API 请求和延迟,并以[基于文本的展示格式](https://prometheus.io/docs/instrumenting/exposition_formats/#exposition-formats)导出到 Prometheus。然后您可以在 Prometheus 中创建事件监控和警报,以监控 API 网关和 API 的健康状况。
## 静态配置
默认情况下,已在默认配置文件 [`config.lua`](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua) 中对 `prometheus` 进行预配置。
要自定义这些值,请将相应的配置添加到 config.yaml 中。例如:
```yaml
plugin_attr:
prometheus: # 插件prometheus 属性
export_uri: /apisix/prometheus/metrics # 设置 Prometheus 指标端点的 URI。
metric_prefix: apisix_ # 设置 APISIX 生成的 Prometheus 指标的前缀。
enable_export_server: true # 启用 Prometheus 导出服务器。
export_addr: # 设置 Prometheus 导出服务器的地址。
ip: 127.0.0.1 # 设置 IP。
port: 9091 # 设置端口。
# metrics: # 为指标创建额外的标签。
# http_status: # 这些指标将以 `apisix_` 为前缀。
# extra_labels: # 设置 http_status 指标的额外标签。
# - upstream_addr: $upstream_addr
# - status: $upstream_status
# expire: 0 # 指标的过期时间(秒)。
# 0 表示指标不会过期。
# http_latency:
# extra_labels: # 设置 http_latency 指标的额外标签。
# - upstream_addr: $upstream_addr
# expire: 0 # 指标的过期时间(秒)。
# 0 表示指标不会过期。
# bandwidth:
# extra_labels: # 设置 bandwidth 指标的额外标签。
# - upstream_addr: $upstream_addr
# expire: 0 # 指标的过期时间(秒)。
# 0 表示指标不会过期。
# default_buckets: # 设置 `http_latency` 指标直方图的默认桶。
# - 10
# - 50
# - 100
# - 200
# - 500
# - 1000
# - 2000
# - 5000
# - 10000
# - 30000
# - 60000
# - 500
```
您可以使用 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)创建 `extra_labels`。请参见[为指标添加额外标签](#为指标添加额外标签)
重新加载 APISIX 以使更改生效。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ------------ | --------| ------ | ------ | ----------------------------------------------------- |
|prefer_name | boolean | 否 | False | 当设置为 `true` 时,则在`prometheus` 指标中导出路由/服务名称而非它们的 `id`。 |
## 指标
Prometheus 中有不同类型的指标。要了解它们之间的区别,请参见[指标类型](https://prometheus.io/docs/concepts/metric_types/)
以下是 `prometheus` 插件默认导出的指标。有关示例,请参见[获取 APISIX 指标](#获取 APISIX 指标)。请注意,一些指标,例如 `apisix_batch_process_entries`,如果没有数据,将不可见。
| 名称 | 类型 | 描述 |
| ----------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| apisix_bandwidth | counter | APISIX 中每个服务消耗的总流量(字节)。 |
| apisix_etcd_modify_indexes | gauge | APISIX 键的 etcd 修改次数。 |
| apisix_batch_process_entries | gauge | 发送数据时批处理中的剩余条目数,例如使用 `http logger` 和其他日志插件。 |
| apisix_etcd_reachable | gauge | APISIX 是否可以访问 etcd。值为 `1` 表示可达,`0` 表示不可达。 |
| apisix_http_status | counter | 从上游服务返回的 HTTP 状态代码。 |
| apisix_http_requests_total | gauge | 来自客户端的 HTTP 请求数量。 |
| apisix_nginx_http_current_connections | gauge | 当前与客户端的连接数量。 |
| apisix_nginx_metric_errors_total | counter | `nginx-lua-prometheus` 错误的总数。 |
| apisix_http_latency | histogram | HTTP 请求延迟(毫秒)。 |
| apisix_node_info | gauge | APISIX 节点的信息,例如主机名和当前的 APISIX 版本号。 |
| apisix_shared_dict_capacity_bytes | gauge | [NGINX 共享字典](https://github.com/openresty/lua-nginx-module#ngxshareddict) 的总容量。 |
| apisix_shared_dict_free_space_bytes | gauge | [NGINX 共享字典](https://github.com/openresty/lua-nginx-module#ngxshareddict) 中剩余的空间。 |
| apisix_upstream_status | gauge | 上游节点的健康检查状态,如果在上游配置了健康检查,则可用。值为 `1` 表示健康,`0` 表示不健康。 |
| apisix_stream_connection_total | counter | 每个 Stream Route 处理的总连接数。 |
## 标签
[标签](https://prometheus.io/docs/practices/naming/#labels) 是指标的属性,用于区分指标。
例如,`apisix_http_status` 指标可以使用 `route` 信息进行标记,以识别 HTTP 状态的来源路由。
以下是 APISIX 指标的非详尽标签及其描述。
### `apisix_http_status` 的标签
以下标签用于区分 `apisix_http_status` 指标。
| 名称 | 描述 |
| ------ | ---------------------------------------------------------------------------------------------------------------------- |
| code | 上游节点返回的 HTTP 响应代码。 |
| route | HTTP 状态来源的路由 ID`prefer_name``false`(默认)时,使用路由 ID`prefer_name``true` 时,使用路由名称。如果请求不匹配任何路由,则默认为空字符串。 |
| matched_uri | 匹配请求的路由 URI。如果请求不匹配任何路由则默认为空字符串。 |
| matched_host | 匹配请求的路由主机。如果请求不匹配任何路由,或路由未配置主机,则默认为空字符串。 |
| service | HTTP 状态来源的服务 ID`prefer_name``false`(默认)时,使用服务 ID`prefer_name``true` 时,使用服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 |
| consumer | 与请求关联的消费者名称。如果请求没有与之关联的消费者,则默认为空字符串。 |
| node | 上游节点的 IP 地址。 |
### `apisix_bandwidth` 的标签
以下标签用于区分 `apisix_bandwidth` 指标。
| 名称 | 描述 |
| ------ | ---------------------------------------------------------------------------------------------------------------------- |
| type | 流量类型,`egress``ingress`。 |
| route | 带宽对应的路由 ID`prefer_name``false`(默认)时,使用路由 ID`prefer_name``true` 时,使用路由名称。如果请求不匹配任何路由,则默认为空字符串。 |
| service | 带宽对应的服务 ID`prefer_name``false`(默认)时,使用服务 ID`prefer_name``true` 时,使用服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 |
| consumer | 与请求关联的消费者名称。如果请求没有与之关联的消费者,则默认为空字符串。 |
| node | 上游节点的 IP 地址。 |
### `apisix_http_latency` 的标签
以下标签用于区分 `apisix_http_latency` 指标。
| 名称 | 描述 |
| ------ | ---------------------------------------------------------------------------------------------------------------------- |
| type | 延迟类型。有关详细信息,请参见 [延迟类型](#延迟类型)。 |
| route | 延迟对应的路由 ID`prefer_name``false`(默认)时,使用路由 ID`prefer_name``true` 时,使用路由名称。如果请求不匹配任何路由,则默认为空字符串。 |
| service | 延迟对应的服务 ID`prefer_name``false`(默认)时,使用服务 ID`prefer_name``true` 时,使用服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 |
| consumer | 与延迟关联的消费者名称。如果请求没有与之关联的消费者,则默认为空字符串。 |
| node | 与延迟关联的上游节点的 IP 地址。 |
#### 延迟类型
`apisix_http_latency` 可以标记为以下三种类型之一:
* `request` 表示从客户端读取第一个字节到最后一个字节发送到客户端之间的时间。
* `upstream` 表示等待上游服务响应的时间。
* `apisix` 表示 `request` 延迟与 `upstream` 延迟之间的差异。
换句话说APISIX 延迟不仅归因于 Lua 处理。应理解为:
```text
APISIX 延迟
= 下游请求时间 - 上游响应时间
= 下游流量延迟 + NGINX 延迟
```
### `apisix_upstream_status` 的标签
以下标签用于区分 `apisix_upstream_status` 指标。
| 名称 | 描述 |
| ------ | ---------------------------------------------------------------------------------------------------------------------- |
| name | 与健康检查配置的上游对应的资源 ID例如 `/apisix/routes/1``/apisix/upstreams/1`。 |
| ip | 上游节点的 IP 地址。 |
| port | 节点的端口号。 |
## 示例
以下示例演示如何在不同场景中使用 `prometheus` 插件。
### 获取 APISIX 指标
以下示例演示如何从 APISIX 获取指标。
默认的 Prometheus 指标端点和其他与 Prometheus 相关的配置可以在 [静态配置](#静态配置) 中找到。如果您希望自定义这些配置,更新 `config.yaml` 并重新加载 APISIX。
如果您在容器化环境中部署 APISIX并希望外部访问 Prometheus 指标端点,请按如下方式更新配置文件并重新加载 APISIX
```yaml title="conf/config.yaml"
plugin_attr:
prometheus:
export_addr:
ip: 0.0.0.0
```
向 APISIX Prometheus 指标端点发送请求:
```shell
curl "http://127.0.0.1:9091/apisix/prometheus/metrics"
```
您应该看到类似以下的输出:
```text
# HELP apisix_bandwidth Total bandwidth in bytes consumed per Service in Apisix
# TYPE apisix_bandwidth counter
apisix_bandwidth{type="egress",route="",service="",consumer="",node=""} 8417
apisix_bandwidth{type="egress",route="1",service="",consumer="",node="127.0.0.1"} 1420
apisix_bandwidth{type="egress",route="2",service="",consumer="",node="127.0.0.1"} 1420
apisix_bandwidth{type="ingress",route="",service="",consumer="",node=""} 189
apisix_bandwidth{type="ingress",route="1",service="",consumer="",node="127.0.0.1"} 332
apisix_bandwidth{type="ingress",route="2",service="",consumer="",node="127.0.0.1"} 332
# HELP apisix_etcd_modify_indexes Etcd modify index for APISIX keys
# TYPE apisix_etcd_modify_indexes gauge
apisix_etcd_modify_indexes{key="consumers"} 0
apisix_etcd_modify_indexes{key="global_rules"} 0
...
```
### 在公共 API 端点上公开 APISIX 指标
以下示例演示如何禁用默认情况下在端口 `9091` 上公开的 Prometheus 导出服务器,并在 APISIX 用于监听其他客户端请求的公共 API 端点上公开 APISIX Prometheus 指标。
在配置文件中禁用 Prometheus 导出服务器,并重新加载 APISIX 以使更改生效:
```yaml title="conf/config.yaml"
plugin_attr:
prometheus:
enable_export_server: false
```
接下来,使用 [`public-api`](../../../zh/latest/plugins/public-api.md) 插件创建一个路由,并为 APISIX 指标公开一个公共 API 端点:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/prometheus-metrics" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"uri": "/apisix/prometheus/metrics",
"plugins": {
"public-api": {}
}
}'
```
向新指标端点发送请求以进行验证:
```shell
curl "http://127.0.0.1:9080/apisix/prometheus/metrics"
```
您应该看到类似以下的输出:
```text
# HELP apisix_http_requests_total 自 APISIX 启动以来客户端请求的总数。
# TYPE apisix_http_requests_total gauge
apisix_http_requests_total 1
# HELP apisix_nginx_http_current_connections 当前 HTTP 连接数量。
# TYPE apisix_nginx_http_current_connections gauge
apisix_nginx_http_current_connections{state="accepted"} 1
apisix_nginx_http_current_connections{state="active"} 1
apisix_nginx_http_current_connections{state="handled"} 1
apisix_nginx_http_current_connections{state="reading"} 0
apisix_nginx_http_current_connections{state="waiting"} 0
apisix_nginx_http_current_connections{state="writing"} 1
...
```
### 监控上游健康状态
以下示例演示如何监控上游节点的健康状态。
使用 `prometheus` 插件创建一个路由,并配置上游的主动健康检查:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "prometheus-route",
"uri": "/get",
"plugins": {
"prometheus": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1,
"127.0.0.1:20001": 1
},
"checks": {
"active": {
"timeout": 5,
"http_path": "/status",
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
},
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [500],
"http_failures": 3,
"tcp_failures": 3
}
}
}
}
}'
```
向 APISIX Prometheus 指标端点发送请求:
```shell
curl "http://127.0.0.1:9091/apisix/prometheus/metrics"
```
您应该看到类似以下的输出:
```text
# HELP apisix_upstream_status 上游健康检查的状态
# TYPE apisix_upstream_status gauge
apisix_upstream_status{name="/apisix/routes/1",ip="54.237.103.220",port="80"} 1
apisix_upstream_status{name="/apisix/routes/1",ip="127.0.0.1",port="20001"} 0
```
这显示上游节点 `httpbin.org:80` 是健康的,而上游节点 `127.0.0.1:20001` 是不健康的。
### 为指标添加额外标签
以下示例演示如何为指标添加额外标签,并在标签值中使用 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。
目前,仅以下指标支持额外标签:
* apisix_http_status
* apisix_http_latency
* apisix_bandwidth
在配置文件中包含以下配置以为指标添加标签,并重新加载 APISIX 以使更改生效:
```yaml title="conf/config.yaml"
plugin_attr:
prometheus: # 插件prometheus
metrics: # 根据 NGINX 变量创建额外标签。
http_status:
extra_labels: # 设置 `http_status` 指标的额外标签。
- upstream_addr: $upstream_addr # 添加一个额外的 `upstream_addr` 标签,其值为 NGINX 变量 $upstream_addr。
- route_name: $route_name # 添加一个额外的 `route_name` 标签,其值为 APISIX 变量 $route_name。
```
请注意,如果您在标签值中定义了一个变量,但它与任何现有的 [APISIX 变量](https://apisix.apache.org/zh/docs/apisix/apisix-variable/) 和 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html) 不对应,则标签值将默认为空字符串。
使用 `prometheus` 插件创建一个路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "prometheus-route",
"name": "extra-label",
"plugins": {
"prometheus": {}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求以进行验证:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该看到 `HTTP/1.1 200 OK` 的响应。
向 APISIX Prometheus 指标端点发送请求:
```shell
curl "http://127.0.0.1:9091/apisix/prometheus/metrics"
```
您应该看到类似以下的输出:
```text
# HELP apisix_http_status APISIX 中每个服务的 HTTP 状态代码
# TYPE apisix_http_status counter
apisix_http_status{code="200",route="1",matched_uri="/get",matched_host="",service="",consumer="",node="54.237.103.220",upstream_addr="54.237.103.220:80",route_name="extra-label"} 1
```
### 使用 Prometheus 监控 TCP/UDP 流量
以下示例演示如何在 APISIX 中收集 TCP/UDP 流量指标。
在 `config.yaml` 中包含以下配置以启用 Stream proxy 和 `prometheus` 插件。重新加载 APISIX 以使更改生效:
```yaml title="conf/config.yaml"
apisix:
proxy_mode: http&stream # 启用 L4 和 L7 代理
stream_proxy: # 配置 L4 代理
tcp:
- 9100 # 设置 TCP 代理监听端口
udp:
- 9200 # 设置 UDP 代理监听端口
stream_plugins:
- prometheus # 为 stream proxy 启用 prometheus
```
使用 `prometheus` 插件创建一个 Stream Route
```shell
curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"prometheus": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向该 Stream Route 发送请求以进行验证:
```shell
curl -i "http://127.0.0.1:9100"
```
您应该看到 `HTTP/1.1 200 OK` 的响应。
向 APISIX Prometheus 指标端点发送请求:
```shell
curl "http://127.0.0.1:9091/apisix/prometheus/metrics"
```
您应该看到类似以下的输出:
```text
# HELP apisix_stream_connection_total APISIX 中每个 Stream Route 处理的总连接数
# TYPE apisix_stream_connection_total counter
apisix_stream_connection_total{route="1"} 1
```

View File

@@ -0,0 +1,379 @@
---
title: proxy-cache
keywords:
- Apache APISIX
- API 网关
- Proxy Cache
description: proxy-cache 插件根据键缓存响应,支持 GET、POST 和 HEAD 请求的磁盘和内存缓存,从而增强 API 性能。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/proxy-cache" />
</head>
## 描述
`proxy-cache` 插件提供了根据缓存键缓存响应的功能。该插​​件支持基于磁盘和基于内存的缓存选项,用于缓存 [GET](https://anything.org/learn/serving-over-http/#get-request)[POST](https://anything.org/learn/serving-over-http/#post-request)[HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) 请求。
可以根据请求 HTTP 方法、响应状态代码、请求标头值等有条件地缓存响应。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------ | -------------- | ------ | ------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| cache_strategy | string | 否 | disk | ["disk","memory"] | 缓存策略。缓存在磁盘还是内存中。 |
| cache_zone | string | 否 | disk_cache_one | | 与缓存策略一起使用的缓存区域。该值应与[配置文件](#static-configurations)中定义的缓存区域之一匹配,并与缓存策略相对应。例如,当使用内存缓存策略时,应该使用内存缓存区域。 |
| cache_key | array[string] | 否 | ["$host", "$request_uri"] | | 用于缓存的键。支持[NGINX 变量](https://nginx.org/en/docs/varindex.html)和值中的常量字符串。变量应该以 `$` 符号为前缀。 |
| cache_bypass | array[string] | 否 | | |一个或多个用于解析值的参数,如果任何值不为空且不等于 `0`,则不会从缓存中检索响应。支持值中的 [NGINX 变量](https://nginx.org/en/docs/varindex.html) 和常量字符串。变量应该以 `$` 符号为前缀。|
| cache_method | array[string] | 否 | ["GET", "HEAD"] | ["GET", "POST", "HEAD"] | 应缓存响应的请求方法。|
| cache_http_status | array[integer] | 否 | [200, 301, 404] | [200, 599] | 应缓存响应的响应 HTTP 状态代码。|
| hide_cache_headers | boolean | 否 | false | | 如果为 true则隐藏 `Expires``Cache-Control` 响应标头。|
| cache_control | boolean | 否 | false | | 如果为 true则遵守 HTTP 规范中的 `Cache-Control` 行为。仅对内存中策略有效。 |
| no_cache | array[string] | 否 | | | 用于解析值的一个或多个参数,如果任何值不为空且不等于 `0`,则不会缓存响应。支持 [NGINX 变量](https://nginx.org/en/docs/varindex.html) 和值中的常量字符串。变量应以 `$` 符号为前缀。 |
| cache_ttl | integer | 否 | 300 | >=1 | 在内存中缓存时的缓存生存时间 (TTL),以秒为单位。要调整在磁盘上缓存时的 TTL请更新[配置文件](#static-configurations) 中的 `cache_ttl`。TTL 值与从上游服务收到的响应标头 [`Cache-Control`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)[`Expires`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires) 中的值一起评估。|
## 静态配置
默认情况下,磁盘缓存时的 `cache_ttl` 和缓存 `zones` 等值已在 [默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua) 中预先配置。
要自定义这些值,请将相应的配置添加到 `config.yaml`。例如:
```yaml
apisix:
proxy_cache:
cache_ttl: 10s # 仅当 `Expires` 和 `Cache-Control` 响应标头均不存在,或者 APISIX 返回
# 由于上游不可用导致 `502 Bad Gateway` 或 `504 Gateway Timeout` 时
# 才会在磁盘上缓存时使用默认缓存 TTL
zones:
- name: disk_cache_one
memory_size: 50m
disk_size: 1G
disk_path: /tmp/disk_cache_one
cache_levels: 1:2
# - name: disk_cache_two
# memory_size: 50m
# disk_size: 1G
# disk_path: "/tmp/disk_cache_two"
# cache_levels: "1:2"
- name: memory_cache
memory_size: 50m
```
重新加载 APISIX 以使更改生效。
## 示例
以下示例演示了如何为不同场景配置 `proxy-cache`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 在磁盘上缓存数据
磁盘缓存策略具有系统重启时数据持久性以及与内存缓存相比具有更大存储容量的优势。它适用于优先考虑耐用性且可以容忍稍大的缓存访问延迟的应用程序。
以下示例演示了如何在路由上使用 `proxy-cache` 插件将数据缓存在磁盘上。
使用磁盘缓存策略时,缓存 TTL 由响应标头 `Expires``Cache-Control` 中的值确定。如果这些标头均不存在,或者 APISIX 由于上游不可用而返回 `502 Bad Gateway``504 Gateway Timeout`,则缓存 TTL 默认为 [配置文件](#static-configuration) 中配置的值。
使用 `proxy-cache` 插件创建路由以将数据缓存在磁盘上:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_strategy": "disk"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应,表明插件已成功启用:
```text
Apisix-Cache-Status: MISS
```
由于在第一次响应之前没有可用的缓存,因此显示 `Apisix-Cache-Status: MISS`
在缓存 TTL 窗口内再次发送相同的请求。您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应,显示缓存已命中:
```text
Apisix-Cache-Status: HIT
```
等待缓存在 TTL 之后过期,然后再次发送相同的请求。您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应,表明缓存已过期:
```text
Apisix-Cache-Status: EXPIRED
```
### 在内存中缓存数据
内存缓存策略具有低延迟访问缓存数据的优势,因为从 RAM 检索数据比从磁盘存储检索数据更快。它还适用于存储不需要长期保存的临时数据,从而可以高效缓存频繁更改的数据。
以下示例演示了如何在路由上使用 `proxy-cache` 插件在内存中缓存数据。
使用 `proxy-cache` 创建路由并将其配置为使用基于内存的缓存:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_strategy": "memory",
"cache_zone": "memory_cache",
"cache_ttl": 10
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应,表明插件已成功启用:
```text
Apisix-Cache-Status: MISS
```
由于在第一次响应之前没有可用的缓存,因此显示 `Apisix-Cache-Status: MISS`
在缓存 TTL 窗口内再次发送相同的请求。您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应,显示缓存已命中:
```text
Apisix-Cache-Status: HIT
```
### 有条件地缓存响应
以下示例演示了如何配置 `proxy-cache` 插件以有条件地缓存响应。
使用 `proxy-cache` 插件创建路由并配置 `no_cache` 属性,这样如果 URL 参数 `no_cache` 和标头 `no_cache` 的值中至少有一个不为空且不等于 `0`,则不会缓存响应:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"no_cache": ["$arg_no_cache", "$http_no_cache"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送一些请求,其中 URL 参数的 `no_cache` 值表示绕过缓存:
```shell
curl -i "http://127.0.0.1:9080/anything?no_cache=1"
```
您应该收到所有请求的 `HTTP/1.1 200 OK` 响应,并且每次都观察到以下标头:
```text
Apisix-Cache-Status: EXPIRED
```
向路由发送一些其他请求,其中 URL 参数 `no_cache` 值为零:
```shell
curl -i "http://127.0.0.1:9080/anything?no_cache=0"
```
您应该收到所有请求的 `HTTP/1.1 200 OK` 响应,并开始看到缓存被命中:
```text
Apisix-Cache-Status: HIT
```
您还可以在 `no_cache` 标头中指定以下值:
```shell
curl -i "http://127.0.0.1:9080/anything" -H "no_cache: 1"
```
响应不应该被缓存:
```text
Apisix-Cache-Status: EXPIRED
```
### 有条件地从缓存中检索响应
以下示例演示了如何配置 `proxy-cache` 插件以有条件地从缓存中检索响应。
使用 `proxy-cache` 插件创建路由并配置 `cache_bypass` 属性,这样如果 URL 参数 `bypass` 和标头 `bypass` 的值中至少有一个不为空且不等于 `0`,则不会从缓存中检索响应:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-cache-route",
"uri": "/anything",
"plugins": {
"proxy-cache": {
"cache_bypass": ["$arg_bypass", "$http_bypass"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送一个请求,其中 URL 参数值为 `bypass`,表示绕过缓存:
```shell
curl -i "http://127.0.0.1:9080/anything?bypass=1"
```
您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应:
```text
Apisix-Cache-Status: BYPASS
```
向路由发送另一个请求,其中 URL 参数 `bypass` 值为零:
```shell
curl -i "http://127.0.0.1:9080/anything?bypass=0"
```
您应该看到带有以下标头的 `HTTP/1.1 200 OK` 响应:
```text
Apisix-Cache-Status: MISS
```
您还可以在 `bypass` 标头中指定以下值:
```shell
curl -i "http://127.0.0.1:9080/anything" -H "bypass: 1"
```
响应应该显示绕过缓存:
```text
Apisix-Cache-Status: BYPASS
```
### 缓存 502 和 504 错误响应代码
当上游服务返回 500 范围内的服务器错误时,`proxy-cache` 插件将缓存响应,当且仅当返回的状态为 `502 Bad Gateway``504 Gateway Timeout`
以下示例演示了当上游服务返回 `504 Gateway Timeout``proxy-cache` 插件的行为。
使用 `proxy-cache` 插件创建路由并配置虚拟上游服务:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-cache-route",
"uri": "/timeout",
"plugins": {
"proxy-cache": { }
},
"upstream": {
"type": "roundrobin",
"nodes": {
"12.34.56.78": 1
}
}
}'
```
生成一些对路由的请求:
```shell
seq 4 | xargs -I{} curl -I "http://127.0.0.1:9080/timeout"
```
您应该会看到类似以下内容的响应:
```text
HTTP/1.1 504 Gateway Time-out
...
Apisix-Cache-Status: MISS
HTTP/1.1 504 Gateway Time-out
...
Apisix-Cache-Status: HIT
HTTP/1.1 504 Gateway Time-out
...
Apisix-Cache-Status: HIT
HTTP/1.1 504 Gateway Time-out
...
Apisix-Cache-Status: HIT
```
但是,如果上游服务返回 `503 Service Temporarily Unavailable`,则响应将不会被缓存。

View File

@@ -0,0 +1,104 @@
---
title: proxy-control
keywords:
- APISIX
- API 网关
- Proxy Control
description: 本文介绍了 Apache APISIX proxy-control 插件的相关操作,你可以使用此插件动态地控制 NGINX 代理的行为。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
使用 `proxy-control` 插件能够动态地控制 NGINX 代理的相关行为。
:::info 重要
此插件需要 APISIX 在 [APISIX-Runtime](../FAQ.md#如何构建-apisix-runtime-环境) 环境上运行。更多信息请参考 [apisix-build-tools](https://github.com/api7/apisix-build-tools)
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------- | ------------- | ----------- | ---------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| request_buffering | boolean | 否 | true | | 如果设置为 `true`,插件将动态设置 [`proxy_request_buffering`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering)。 |
## 启用插件
以下示例展示了如何在指定路由上启用 `proxy-control` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/upload",
"plugins": {
"proxy-control": {
"request_buffering": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
启用插件后,使用 `curl` 命令请求该路由进行一个大文件的上传测试:
```shell
curl -i http://127.0.0.1:9080/upload -d @very_big_file
```
如果在错误日志中没有找到关于 "a client request body is buffered to a temporary file" 的信息,则说明插件生效。
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d
{
"uri": "/upload",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,145 @@
---
title: proxy-mirror
keywords:
- APISIX
- API 网关
- Proxy Mirror
description: proxy-mirror 插件将入口流量复制到 APISIX 并将其转发到指定的上游,而不会中断常规服务。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/proxy-mirror" />
</head>
## 描述
`proxy-mirror` 插件将传入流量复制到 APISIX 并将其转发到指定的上游,而不会中断常规服务。您可以将插件配置为镜像所有流量或仅镜像一部分流量。该机制有利于一些用例,包括故障排除、安全检查、分析等。
请注意APISIX 会忽略接收镜像流量的上游主机的任何响应。
## 参数
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---- | ------ | ------ | ------ | ------ | ------------------------------------------------------------------------------------------------------- |
| host | string | 是 | | | 将镜像流量转发到的主机的地址。该地址应包含方案但不包含路径,例如 `http://127.0.0.1:8081`。 |
| path | string | 否 | | | 将镜像流量转发到的主机的路径。如果未指定,则默认为路由的当前 URI 路径。如果插件正在镜像 gRPC 流量,则不适用。 |
| path_concat_mode | string | 否 | replace | ["replace", "prefix"] | 指定 `path` 时的连接模式。设置为 `replace` 时,配置的 `path` 将直接用作将镜像流量转发到的主机的路径。设置为 `prefix` 时,转发到的路径将是配置的 `path`,附加路由的请求 URI 路径。如果插件正在镜像 gRPC 流量,则不适用。 |
| sample_ratio | number | 否 | 1 | [0.00001, 1] | 将被镜像的请求的比例。默认情况下,所有流量都会被镜像。|
## 静态配置
默认情况下,插件的超时值在[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中预先配置。
要自定义这些值,请将相应的配置添加到 `config.yaml`。例如:
```yaml
plugin_attr:
proxy-mirror:
timeout:
connect: 60s
read: 60s
send: 60s
```
重新加载 APISIX 以使更改生效。
## 示例
以下示例演示了如何为不同场景配置 `proxy-mirror`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 镜像部分流量
以下示例演示了如何配置 `proxy-mirror` 以将 50% 的流量镜像到路由并将其转发到另一个上游服务。
启动一个示例 NGINX 服务器以接收镜像流量:
```shell
docker run -p 8081:80 --name nginx nginx
```
您应该在终端会话中看到 NGINX 访问日志和错误日志。
打开一个新的终端会话并使用 `proxy-mirror` 创建一个路由来镜像 50% 的流量:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "traffic-mirror-route",
"uri": "/get",
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1:8081",
"sample_ratio": 0.5
}
},
"upstream": {
"nodes": {
"httpbin.org": 1
},
"type": "roundrobin"
}
}'
```
发送生成几个请求到路由:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该会收到所有请求的 `HTTP/1.1 200 OK` 响应。
导航回 NGINX 终端会话,您应该会看到一些访问日志条目,大约是生成的请求数量的一半:
```text
172.17.0.1 - - [29/Jan/2024:23:11:01 +0000] "GET /get HTTP/1.1" 404 153 "-" "curl/7.64.1" "-"
```
这表明 APISIX 已将请求镜像到 NGINX 服务器。此处HTTP 响应状态为 `404`,因为示例 NGINX 服务器未实现路由。
### 配置镜像超时
以下示例演示了如何更新插件的默认连接、读取和发送超时。当将流量镜像到非常慢的后端服务时,这可能很有用。
由于请求镜像是作为子请求实现的,子请求中的过度延迟可能导致原始请求被阻止。默认情况下,连接、读取和发送超时设置为 60 秒。要更新这些值,您可以在配置文件的 `plugin_attr` 部分中配置它们,如下所示:
```yaml title="conf/config.yaml"
plugin_attr:
proxy-mirror:
timeout:
connect: 2000ms
read: 2000ms
send: 2000ms
```
重新加载 APISIX 以使更改生效。

View File

@@ -0,0 +1,509 @@
---
title: proxy-rewrite
keywords:
- Apache APISIX
- API 网关
- Plugin
- Proxy Rewrite
- proxy-rewrite
description: proxy-rewrite 插件支持重写 APISIX 转发到上游服务的请求。使用此插件,您可以修改 HTTP 方法、请求目标上游地址、请求标头等。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/proxy-rewrite" />
</head>
## 描述
`proxy-rewrite` 插件支持重写 APISIX 转发到上游服务的请求。使用此插件,您可以修改 HTTP 方法、请求目标上游地址、请求标头等。
## 属性
| 名称 | 类型 | 必需 | 默认值 | 有效值 | 描述 |
|-----------------------------|-----------|----------|---------|------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| uri | string | 否 | | | 新的上游 URI 路径。值支持 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。例如,`$arg_name`。 |
| method | string | 否 | | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | 要使用的重写请求的 HTTP 方法。 |
| regex_uri | array[string] | 否 | | | 用于匹配客户端请求的 URI 路径并组成新的上游 URI 路径的正则表达式。当同时配置 `uri``regex_uri` 时,`uri` 具有更高的优先级。该数组应包含一个或多个 **键值对**,其中键是用于匹配 URI 的正则表达式,值是新的上游 URI 路径。例如,对于 `["^/iresty/(. *)/(. *)", "/$1-$2", ^/theothers/*", "/theothers"]`,如果请求最初发送到 `/iresty/hello/world`,插件会将上游 URI 路径重写为 `/iresty/hello-world`;如果请求最初发送到 `/theothers/hello/world`,插件会将上游 URI 路径重写为 `/theothers`。|
| host | string | 否 | | | 设置 [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) 请求标头。|
| headers | object | 否 | | | 要执行的标头操作。可以设置为动作动词 `add``remove` 和/或 `set` 的对象;或由要 `set` 的标头组成的对象。当配置了多个动作动词时,动作将按照“添加”、“删除”和“设置”的顺序执行。|
| headers.add | object | 否 | | | 要附加到请求的标头。如果请求中已经存在标头,则会附加标头值。标头值可以设置为常量、一个或多个 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html),或者 `regex_uri` 的匹配结果(使用变量,例如 `$1-$2-$3`)。|
| headers.set | object | 否 | | | 要设置请求的标头。如果请求中已经存在标头,则会覆盖标头值。标头值可以设置为常量、一个或多个 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html),或者 `regex_uri` 的匹配结果(使用变量,例如 `$1-$2-$3`)。不应将其用于设置 `Host`。|
| headers.remove | array[string] | 否 | | | 从请求中删除的标头。
| use_real_request_uri_unsafe | boolean | 否 | false | | 如果为 True则绕过 URI 规范化并允许完整的原始请求 URI。启用此选项被视为不安全。|
## 示例
下面的示例说明如何在不同场景中在路由上配置 `proxy-rewrite`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 重写主机标头
以下示例演示了如何修改请求中的 `Host` 标头。请注意,您不应使用 `headers.set` 来设置 `Host` 标头。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins": {
"proxy-rewrite": {
"host": "myapisix.demo"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
`/headers` 发送请求以检查发送到上游的所有请求标头:
```shell
curl "http://127.0.0.1:9080/headers"
```
您应该看到类似于以下内容的响应:
```text
{
"headers": {
"Accept": "*/*",
"Host": "myapisix.demo",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id": "Root=1-64fef198-29da0970383150175bd2d76d",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
### 重写 URI 并设置标头
以下示例演示了如何重写请求上游 URI 并设置其他标头值。如果客户端请求中存在相同的标头,则插件中设置的相应标头值将覆盖客户端请求中存在的值。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/",
"plugins": {
"proxy-rewrite": {
"uri": "/anything",
"headers": {
"set": {
"X-Api-Version": "v1",
"X-Api-Engine": "apisix"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl "http://127.0.0.1:9080/" -H '"X-Api-Version": "v2"'
```
您应该看到类似于以下内容的响应:
```text
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id": "Root=1-64fed73a-59cd3bd640d76ab16c97f1f1",
"X-Api-Engine": "apisix",
"X-Api-Version": "v1",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "::1, 103.248.35.179",
"url": "http://localhost/anything"
}
```
注意到其中两个标头都存在,以及插件中配置的 `X-Api-Version` 标头值覆盖了请求中传递的标头值。
### 重写 URI 并附加标头
以下示例演示了如何重写请求上游 URI 并附加其他标头值。如果客户端请求中存在相同的标头,则它们的标头值将附加到插件中配置的标头值。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/",
"plugins": {
"proxy-rewrite": {
"uri": "/headers",
"headers": {
"add": {
"X-Api-Version": "v1",
"X-Api-Engine": "apisix"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl "http://127.0.0.1:9080/" -H '"X-Api-Version": "v2"'
```
您应该会看到类似以下内容的响应:
```text
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id": "Root=1-64fed73a-59cd3bd640d76ab16c97f1f1",
"X-Api-Engine": "apisix",
"X-Api-Version": "v1,v2",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
请注意,两个标头均存在,并且插件中配置的 `X-Api-Version` 标头值均附加在请求中传递的标头值上。
### 删除现有标头
以下示例演示了如何删除现有标头 `User-Agent`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins": {
"proxy-rewrite": {
"headers": {
"remove":[
"User-Agent"
]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求来验证指定的标头是否被删除:
```shell
curl "http://127.0.0.1:9080/headers"
```
您应该看到类似以下的响应,其中 `User-Agen` 标头已被移除:
```text
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-64fef302-07f2b13e0eb006ba776ad91d",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
### 使用 RegEx 重写 URI
以下示例演示了如何解析原始上游 URI 路径中的文本并使用它们组成新的上游 URI 路径。在此示例中APISIX 配置为将所有请求从 `/test/user/agent` 转发到 `/user-agent`
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"uri": "/test/*",
"plugins": {
# highlight-start
"proxy-rewrite": {
"regex_uri": ["^/test/(.*)/(.*)", "/$1-$2"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求到 `/test/user/agent`,检查是否被重定向到 `/user-agent`
```shell
curl "http://127.0.0.1:9080/test/user/agent"
```
您应该会看到类似以下内容的响应:
```text
{
"user-agent": "curl/8.2.1"
}
```
### 添加 URL 参数
以下示例演示了如何向请求添加 URL 参数。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/get",
"plugins": {
"proxy-rewrite": {
"uri": "/get?arg1=apisix&arg2=plugin"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求来验证 URL 参数是否也转发给了上游:
```shell
curl "http://127.0.0.1:9080/get"
```
您应该会看到类似以下内容的响应:
```text
{
"args": {
"arg1": "apisix",
"arg2": "plugin"
},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id": "Root=1-64fef6dc-2b0e09591db7353a275cdae4",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "127.0.0.1, 103.248.35.148",
# highlight-next-line
"url": "http://127.0.0.1/get?arg1=apisix&arg2=plugin"
}
```
### 重写 HTTP 方法
以下示例演示如何将 GET 请求重写为 POST 请求。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "proxy-rewrite-route",
"methods": ["GET"],
"uri": "/get",
"plugins": {
"proxy-rewrite": {
"uri": "/anything",
"method":"POST"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
`/get` 发送 GET 请求,以验证它是否转换为向 `/anything` 发送 POST 请求:
```shell
curl "http://127.0.0.1:9080/get"
```
您应该会看到类似以下内容的响应:
```text
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id": "Root=1-64fef7de-0c63387645353998196317f2",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "POST",
"origin": "::1, 103.248.35.179",
"url": "http://localhost/anything"
}
```
### 将消费者名称转发到上游
以下示例演示了如何将成功验证的消费者名称转发到上游服务。例如,您将使用 `key-auth` 作为身份验证方法。
创建消费者 `JohnDoe`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "JohnDoe"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/JohnDoe/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
接下来,创建一个启用密钥认证的路由,配置 `proxy-rewrite` 以将消费者名称添加到标头,并删除认证密钥,以使其对上游服务不可见:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "consumer-restricted-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"proxy-rewrite": {
"headers": {
"set": {
"X-Apisix-Consumer": "$consumer_name"
},
"remove": [ "Apikey" ]
}
}
},
"upstream" : {
"nodes": {
"httpbin.org":1
}
}
}'
```
以消费者 `JohnDoe` 的身份向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key'
```
您应该收到一个包含以下主体的 `HTTP/1.1 200 OK` 响应:
```text
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.4.0",
"X-Amzn-Trace-Id": "Root=1-664b01a6-2163c0156ed4bff51d87d877",
"X-Apisix-Consumer": "JohnDoe",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "172.19.0.1, 203.12.12.12",
"url": "http://127.0.0.1/get"
}
```
向路由发送另一个请求,不带有有效凭证:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该收到 `HTTP/1.1 403 Forbidden` 响应。

View File

@@ -0,0 +1,242 @@
---
title: public-api
keywords:
- APISIX
- API 网关
- Public API
description: public-api 插件公开了一个内部 API 端点,使其可被公开访问。该插件的主要用途之一是公开由其他插件创建的内部端点。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/public-api" />
</head>
## 描述
`public-api` 插件公开了一个内部 API 端点,使其可被公开访问。该插件的主要用途之一是公开由其他插件创建的内部端点。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|------|--------|-------|-------|------|------|
| uri | string | 否 | | | 内部端点的 URI。如果未配置则暴露路由的 URI。|
## 示例
以下示例展示了如何在不同场景中配置 `public-api`
### 在自定义端点暴露 Prometheus 指标
以下示例演示如何禁用默认在端口 `9091` 上暴露端点的 Prometheus 导出服务器,并在 APISIX 用于监听其他客户端请求的端口 `9080` 上,通过新的公共 API 端点暴露 APISIX 的 Prometheus 指标。
此外,还会配置路由,使内部端点 `/apisix/prometheus/metrics` 通过自定义端点对外公开。
:::caution
如果收集了大量指标,插件可能会占用大量 CPU 资源用于计算,从而影响正常请求的处理。
为了解决这个问题APISIX 使用 [特权代理进程](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent) ,并将指标计算卸载至独立进程。如果使用配置文件中 `plugin_attr.prometheus.export_addr` 设定的指标端点,该优化将自动生效。但如果通过 `public-api` 插件暴露指标端点,则不会受益于此优化。
:::
在配置文件中禁用 Prometheus 导出服务器,并重新加载 APISIX 以使更改生效:
```yaml
plugin_attr:
prometheus:
enable_export_server: false
```
接下来,创建一个带有 `public-api` 插件的路由,并为 APISIX 指标暴露一个公共 API 端点。你应将路由的 `uri` 设置为自定义端点路径,并将插件的 `uri` 设置为要暴露的内部端点。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H 'X-API-KEY: ${admin_key}' \
-d '{
"id": "prometheus-metrics",
"uri": "/prometheus_metrics",
"plugins": {
"public-api": {
"uri": "/apisix/prometheus/metrics"
}
}
}'
```
向自定义指标端点发送请求:
```shell
curl http://127.0.0.1:9080/prometheus_metrics
```
你应看到类似以下的输出:
```text
# HELP apisix_http_requests_total The total number of client requests since APISIX started
# TYPE apisix_http_requests_total gauge
apisix_http_requests_total 1
# HELP apisix_nginx_http_current_connections Number of HTTP connections
# TYPE apisix_nginx_http_current_connections gauge
apisix_nginx_http_current_connections{state="accepted"} 1
apisix_nginx_http_current_connections{state="active"} 1
apisix_nginx_http_current_connections{state="handled"} 1
apisix_nginx_http_current_connections{state="reading"} 0
apisix_nginx_http_current_connections{state="waiting"} 0
apisix_nginx_http_current_connections{state="writing"} 1
...
```
### 暴露批量请求端点
以下示例展示了如何使用 `public-api` 插件来暴露 `batch-requests` 插件的端点,该插件用于将多个请求组合成一个请求,然后将它们发送到网关。
创建一个样本路由到 httpbin 的 `/anything` 端点,用于验证目的:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "httpbin-anything",
"uri": "/anything",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
创建一个带有 `public-api` 插件的路由,并将路由的 `uri` 设置为要暴露的内部端点:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "batch-requests",
"uri": "/apisix/batch-requests",
"plugins": {
"public-api": {}
}
}'
```
向暴露的批量请求端点发送一个包含 GET 和 POST 请求的流水线请求:
```shell
curl "http://127.0.0.1:9080/apisix/batch-requests" -X POST -d '
{
"pipeline": [
{
"method": "GET",
"path": "/anything"
},
{
"method": "POST",
"path": "/anything",
"body": "a post request"
}
]
}'
```
您应该会收到两个请求的响应,类似于以下内容:
```json
[
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
},
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
}
]
```
如果您希望在自定义端点处暴露批量请求端点,请创建一个带有 `public-api` 插件的路由。您应该将路由的 `uri` 设置为自定义端点路径,并将插件的 uri 设置为要暴露的内部端点。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "batch-requests",
"uri": "/batch-requests",
"plugins": {
"public-api": {
"uri": "/apisix/batch-requests"
}
}
}'
```
现在批量请求端点应该被暴露为 `/batch-requests`,而不是 `/apisix/batch-requests`
向暴露的批量请求端点发送一个包含 GET 和 POST 请求的流水线请求:
```shell
curl "http://127.0.0.1:9080/batch-requests" -X POST -d '
{
"pipeline": [
{
"method": "GET",
"path": "/anything"
},
{
"method": "POST",
"path": "/anything",
"body": "a post request"
}
]
}'
```
您应该会收到两个请求的响应,类似于以下内容:
```json
[
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
},
{
"reason": "OK",
"body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n",
"headers": {
...
},
"status": 200
}
]
```

View File

@@ -0,0 +1,202 @@
---
title: real-ip
keywords:
- Apache APISIX
- API 网关
- Plugin
- Real IP
description: real-ip 插件允许 Apache APISIX 通过 HTTP 请求头或 HTTP 查询字符串中传递的 IP 地址设置客户端的真实 IP。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/real-ip" />
</head>
## 描述
`real-ip` 插件允许 APISIX 通过 HTTP 请求头或 HTTP 查询字符串中传递的 IP 地址设置客户端的真实 IP。当 APISIX 位于反向代理之后时,此功能尤其有用,因为在这种情况下,代理可能会被视为请求发起客户端。
该插件在功能上类似于 NGINX 的 [ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html),但提供了更多的灵活性。
## 属性
| 名称 | 类型 | 是否必需 | 默认值 | 有效值 | 描述 |
|-------------------|---------------|----------|--------|----------------------------|----------------------------------------------------------------------|
| source | string | 是 | | | 内置变量,例如 `http_x_forwarded_for``arg_realip`。变量值应为一个有效的 IP 地址,表示客户端的真实 IP 地址,可选地包含端口。 |
| trusted_addresses | array[string] | 否 | | IPv4 或 IPv6 地址数组(接受 CIDR 表示法) | 已知会发送正确替代地址的可信地址。此配置设置 [`set_real_ip_from`](https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from) 指令。 |
| recursive | boolean | 否 | false | | 如果为 false则将匹配可信地址之一的原始客户端地址替换为配置的 `source` 中发送的最后一个地址。<br />如果为 true则将匹配可信地址之一的原始客户端地址替换为配置的 `source` 中发送的最后一个非可信地址。 |
:::note
如果 `source` 属性中设置的地址丢失或者无效,该插件将不会更改客户端地址。
:::
## 示例
以下示例展示了如何在不同场景中配置 `real-ip`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 从 URI 参数获取真实客户端地址
以下示例演示了如何使用 URI 参数更新客户端 IP 地址。
创建如下路由。您应配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从 URL 参数 `realip` 获取值。使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 和端口是否实际更新。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "real-ip-route",
"uri": "/get",
"plugins": {
"real-ip": {
"source": "arg_realip",
"trusted_addresses": ["127.0.0.0/24"]
},
"response-rewrite": {
"headers": {
"remote_addr": "$remote_addr",
"remote_port": "$remote_port"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送带有 URL 参数中的真实 IP 和端口的请求:
```shell
curl -i "http://127.0.0.1:9080/get?realip=1.2.3.4:9080"
```
您应看到响应包含以下头:
```text
remote-addr: 1.2.3.4
remote-port: 9080
```
### 从请求头获取真实客户端地址
以下示例展示了当 APISIX 位于反向代理(例如负载均衡器)之后时,如何设置真实客户端 IP此时代理在 [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) 请求头中暴露了真实客户端 IP。
创建如下路由。您应配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。使用 response-rewrite 插件设置响应头,以验证客户端 IP 是否实际更新。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "real-ip-route",
"uri": "/get",
"plugins": {
"real-ip": {
"source": "http_x_forwarded_for",
"trusted_addresses": ["127.0.0.0/24"]
},
"response-rewrite": {
"headers": {
"remote_addr": "$remote_addr"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应看到响应包含以下头:
```text
remote-addr: 10.26.3.19
```
IP 地址应对应于请求发起客户端的 IP 地址。
### 在多个代理之后获取真实客户端地址
以下示例展示了当 APISIX 位于多个代理之后时,如何获取真实客户端 IP此时 [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) 请求头包含了一系列代理 IP 地址。
创建如下路由。您应配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。将 `recursive` 设置为 `true`,以便将匹配可信地址之一的原始客户端地址替换为配置的 `source` 中发送的最后一个非可信地址。然后,使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际更新。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "real-ip-route",
"uri": "/get",
"plugins": {
"real-ip": {
"source": "http_x_forwarded_for",
"recursive": true,
"trusted_addresses": ["192.128.0.0/16", "127.0.0.0/24"]
},
"response-rewrite": {
"headers": {
"remote_addr": "$remote_addr"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" \
-H "X-Forwarded-For: 127.0.0.2, 192.128.1.1, 127.0.0.1"
```
您应看到响应包含以下头:
```text
remote-addr: 127.0.0.2
```

View File

@@ -0,0 +1,177 @@
---
title: redirect
keywords:
- Apache APISIX
- API 网关
- Plugin
- Redirect
description: 本文介绍了关于 Apache APISIX `redirect` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`redirect` 插件可用于配置 URI 重定向。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|---------------------|---------------|-----|-------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| http_to_https | boolean | 否 | false | [true,false] | 当设置为 `true` 并且请求是 HTTP 时,它将被重定向具有相同 URI 和 301 状态码的 HTTPS原 URI 的查询字符串也将包含在 Location 头中。 |
| uri | string | 否 | | | 要重定向到的 URI可以包含 NGINX 变量。例如:`/test/index.htm``$uri/index.html``${uri}/index.html``https://example.com/foo/bar`。如果你引入了一个不存在的变量,它不会报错,而是将其视为一个空变量。 |
| regex_uri | array[string] | 否 | | | 将来自客户端的 URL 与正则表达式匹配并重定向。当匹配成功后使用模板替换发送重定向到客户端,如果未匹配成功会将客户端请求的 URI 转发至上游。和 `regex_uri` 不可以同时存在。例如:["^/iresty/(.)/(.)/(.*)","/$1-$2-$3"] 第一个元素代表匹配来自客户端请求的 URI 正则表达式,第二个元素代表匹配成功后发送重定向到客户端的 URI 模板。 |
| ret_code | integer | 否 | 302 | [200, ...] | HTTP 响应码 |
| encode_uri | boolean | 否 | false | [true,false] | 当设置为 `true` 时,对返回的 `Location` Header 按照 [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986) 的编码格式进行编码。 |
| append_query_string | boolean | 否 | false | [true,false] | 当设置为 `true` 时,将原始请求中的查询字符串添加到 `Location` Header。如果已配置 `uri``regex_uri` 已经包含查询字符串,则请求中的查询字符串将附加一个`&`。如果你已经处理过查询字符串(例如,使用 NGINX 变量 `$request_uri`),请不要再使用该参数以避免重复。 |
:::note
* `http_to_https``uri``regex_uri` 只能配置其中一个属性。
* `http_to_https`、和 `append_query_string` 只能配置其中一个属性。
* 当开启 `http_to_https` 时,重定向 URL 中的端口将按如下顺序选取一个值(按优先级从高到低排列)
* 从配置文件(`conf/config.yaml`)中读取 `plugin_attr.redirect.https_port`
* 如果 `apisix.ssl` 处于开启状态,读取 `apisix.ssl.listen` 并从中随机选一个 `port`
* 使用 443 作为默认 `https port`
:::
## 启用插件
以下示例展示了如何在指定路由中启用 `redirect` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/test/index.html",
"plugins": {
"redirect": {
"uri": "/test/default.html",
"ret_code": 301
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
```
你也可以在新的 URI 中使用 NGINX 内置的任意变量:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/test",
"plugins": {
"redirect": {
"uri": "$uri/index.html",
"ret_code": 301
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
```
## 测试插件
通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
```shell
curl http://127.0.0.1:9080/test/index.html -i
```
```
HTTP/1.1 301 Moved Permanently
Date: Wed, 23 Oct 2019 13:48:23 GMT
Content-Type: text/html
Content-Length: 166
Connection: keep-alive
Location: /test/default.html
...
```
通过上述返回结果,可以看到响应码和响应头中的 `Location` 参数,它表示该插件已启用。
以下示例展示了如何将 HTTP 重定向到 HTTPS
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {
"redirect": {
"http_to_https": true
}
}
}'
```
基于上述例子进行测试:
```shell
curl http://127.0.0.1:9080/hello -i
```
```
HTTP/1.1 301 Moved Permanently
...
Location: https://127.0.0.1:9443/hello
...
```
## 删除插件
当你需要禁用 `redirect` 插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/test/index.html",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
```

View File

@@ -0,0 +1,142 @@
---
title: referer-restriction
keywords:
- APISIX
- API 网关
- Referer restriction
description: 本文介绍了 Apache APISIX referer-restriction 插件的使用方法,通过该插件可以将 referer 请求头中的域名加入黑名单或者白名单来限制其对服务或路由的访问。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`referer-restriction` 插件允许用户将 `Referer` 请求头中的域名列入白名单或黑名单来限制该域名对服务或路由的访问。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------- | ------------- | ------ | ------ | ------ | -------------------------------- |
| whitelist | array[string] | 否 | | | 白名单域名列表。域名开头可以用 `*` 作为通配符。 |
| blacklist | array[string] | 否 | | | 黑名单域名列表。域名开头可以用 `*` 作为通配符。 |
| message | string | 否 | "Your referer host is not allowed" | [1, 1024] | 在未允许访问的情况下返回的信息。 |
| bypass_missing | boolean | 否 | false | | 当设置为 `true` 时,如果 `Referer` 请求头不存在或格式有误,将绕过检查。 |
:::info IMPORTANT
`whitelist``blacklist` 属性无法同时在同一个服务或路由上使用,只能使用其中之一。
:::
## 启用插件
以下示例展示了如何在特定路由上启用 `referer-restriction` 插件,并配置 `whitelist``bypass_missing` 属性:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"referer-restriction": {
"bypass_missing": true,
"whitelist": [
"xx.com",
"*.xx.com"
]
}
}
}'
```
## 测试插件
通过上述命令启用插件后,你可以在请求中添加 `Referer: http://xx.com/x` 测试插件:
```shell
curl http://127.0.0.1:9080/index.html -H 'Referer: http://xx.com/x'
```
返回的 HTTP 响应头中带有 `200` 状态码则表示访问成功:
```shell
HTTP/1.1 200 OK
...
```
接下来,将请求设置为 `Referer: http://yy.com/x`
```shell
curl http://127.0.0.1:9080/index.html -H 'Referer: http://yy.com/x'
```
返回的 HTTP 响应头中带有 `403` 状态码,并在响应体中带有 `message` 属性值,代表访问被阻止:
```shell
HTTP/1.1 403 Forbidden
...
{"message":"Your referer host is not allowed"}
```
因为启用插件时会将属性 `bypass_missing` 设置为 `true`,所以未指定 `Refer` 请求头的请求将跳过检查:
```shell
curl http://127.0.0.1:9080/index.html
```
返回的 HTTP 响应头中带有 `200` 状态码,代表访问成功:
```shell
HTTP/1.1 200 OK
...
```
## 删除插件
当你需要删除该插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,292 @@
---
title: request-id
keywords:
- APISIX
- API 网关
- Request ID
description: request-id 插件为通过 APISIX 代理的每个请求添加一个唯一的 ID可用于跟踪 API 请求。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`request-id` 插件为每个通过 APISIX 代理的请求添加一个唯一 ID可用于跟踪 API 请求。如果请求在 `header_name` 对应的 header 中带有 ID则插件将使用 header 值作为唯一 ID而不会用自动生成的 ID 进行覆盖。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------------- | ------- | -------- | -------------- | ------ | ------------------------------ |
| header_name | string | 否 | "X-Request-Id" | | 携带请求唯一 ID 的标头的名称。请注意,如果请求在 `header_name` 标头中携带 ID则插件将使用标头值作为唯一 ID并且不会用生成的 ID 覆盖它。|
| include_in_response | 布尔值 | 否 | true | | 如果为 true则将生成的请求 ID 包含在响应标头中,其中标头的名称是 `header_name` 值。|
| algorithm | string | 否 | "uuid" | ["uuid","nanoid","range_id"] | 用于生成唯一 ID 的算法。设置为 `uuid` 时,插件会生成一个通用唯一标识符。设置为 `nanoid`插件会生成一个紧凑的、URL 安全的 ID。设置为 `range_id` 时,插件会生成具有特定参数的连续 ID。|
| range_id | object | 否 | | |使用 `range_id` 算法生成请求 ID 的配置。|
| range_id.char_set | string | 否 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789" | 最小长度 6 | 用于 `range_id` 算法的字符集。|
| range_id.length | integer | 否 | 16 | >=6 | 用于 `range_id` 算法的生成的 ID 的长度。|
## 示例
以下示例演示了如何在不同场景中配置“request-id”。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 将请求 ID 附加到默认响应标头
以下示例演示了如何在路由上配置 `request-id`,如果请求中未传递标头值,则将生成的请求 ID 附加到默认的 `X-Request-Id` 响应标头。当在请求中设置 `X-Request-Id` 标头时,插件将把请求标头中的值作为请求 ID。
使用其默认配置(明确定义)创建带有 `request-id` 插件的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-id-route",
"uri": "/anything",
"plugins": {
"request-id": {
"header_name": "X-Request-Id",
"include_in_response": true,
"algorithm": "uuid"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到一个 `HTTP/1.1 200 OK` 响应,并且会看到响应包含 `X-Request-Id` 标头和生成的 ID
```text
X-Request-Id: b9b2c0d4-d058-46fa-bafc-dd91a0ccf441
```
使用标头中的自定义请求 ID 向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -H 'X-Request-Id: some-custom-request-id'
```
您应该会收到 `HTTP/1.1 200 OK` 响应,并看到响应包含带有自定义请求 ID 的 `X-Request-Id` 标头:
```text
X-Request-Idsome-custom-request-id
```
### 将请求 ID 附加到自定义响应标头
以下示例演示如何在路由上配置 `request-id`,将生成的请求 ID 附加到指定的标头。
使用 `request-id` 插件创建路由,以定义带有请求 ID 的自定义标头,并将请求 ID 包含在响应标头中:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-id-route",
"uri": "/anything",
"plugins": {
"request-id": {
"header_name": "X-Req-Identifier",
"include_in_response": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到一个 `HTTP/1.1 200 OK` 响应,并看到响应包含带有生成 ID 的 `X-Req-Identifier` 标头:
```text
X-Req-Identifier1c42ff59-ee4c-4103-a980-8359f4135b21
```
### 在响应标头中隐藏请求 ID
以下示例演示如何在路由上配置 `request-id`,将生成的请求 ID 附加到指定的标头。包含请求 ID 的标头应转发到上游服务,但不会在响应标头中返回。
使用 `request-id` 插件创建路由,以定义带有请求 ID 的自定义标头,而不在响应标头中包含请求 ID
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-id-route",
"uri": "/anything",
"plugins": {
"request-id": {
"header_name": "X-Req-Identifier",
"include_in_response": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到 `HTTP/1.1 200 OK` 响应,并在响应标头中看到 `X-Req-Identifier` 标头。在响应主体中,您应该看到:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-6752748c-7d364f48564508db1e8c9ea8",
"X-Forwarded-Host": "127.0.0.1",
"X-Req-Identifier": "268092bc-15e1-4461-b277-bf7775f2856f"
},
...
}
```
这表明请求 ID 已转发到上游服务,但未在响应标头中返回。
### 使用 `nanoid` 算法
以下示例演示如何在路由上配置 `request-id` 并使用 `nanoid` 算法生成请求 ID。
使用 `request-id` 插件创建路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-id-route",
"uri": "/anything",
"plugins": {
"request-id": {
"algorithm": "nanoid"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到一个 `HTTP/1.1 200 OK` 响应,并看到响应包含 `X-Req-Identifier` 标头,其中的 ID 使用 `nanoid` 算法生成:
```text
X-Request-Id: kepgHWCH2ycQ6JknQKrX2
```
### 全局和在路由上附加请求 ID
以下示例演示如何将 `request-id` 配置为全局插件并在路由上附加两个 ID。
`request-id` 插件创建全局规则,将请求 ID 添加到自定义标头:
```shell
curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT -d '{
"id": "rule-for-request-id",
"plugins": {
"request-id": {
"header_name": "Global-Request-ID"
}
}
}'
```
使用 `request-id` 插件创建路由,将请求 ID 添加到不同的自定义标头:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-id-route",
"uri": "/anything",
"plugins": {
"request-id": {
"header_name": "Route-Request-ID"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应,并看到响应包含以下标头:
```text
Global-Request-ID2e9b99c1-08ed-4a74-b347-49c0891b07ad
Route-Request-IDd755666b-732c-4f0e-a30e-a7a71ace4e26
```

View File

@@ -0,0 +1,528 @@
---
title: request-validation
keywords:
- APISIX
- API 网关
- Request Validation
description: request-validation 插件会在将请求转发到上游服务之前对其进行验证。此插件使用 JSON Schema 进行验证,并且可以验证请求的标头和正文。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/request-validation" />
</head>
## 描述
`request-validation` 插件会在将请求转发到上游服务之前对其进行验证。此插件使用 [JSON Schema](https://github.com/api7/jsonschema) 进行验证,并且可以验证请求的标头和正文。
请参阅 [JSON Schema 规范](https://json-schema.org/specification) 了解有关语法的更多信息。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------ | ----------- | ------- | ----- | --------------------------------- |
| header_schema | object | 否 | | | `header` 数据的 `schema` 数据结构。 |
| body_schema | object | 否 | | | `body` 数据的 `schema` 数据结构。 |
| rejected_code | integer | 否 | 400 | [200,...,599] | 当请求被拒绝时要返回的状态码。 |
| rejected_msg | string | 否 | | | 当请求被拒绝时返回的信息。 |
:::note
`header_schema``body_schema` 属性至少需要配置其一。
:::
## 示例
以下示例演示了如何针对不同场景配置 `request-validation`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 验证请求标头
下面的示例演示如何根据定义的 JSON Schema 验证请求标头,该模式需要两个特定的标头和标头值符合指定的要求。
使用 `request-validation` 插件创建路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "request-validation-route",
"uri": "/get",
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"required": ["User-Agent", "Host"],
"properties": {
"User-Agent": {
"type": "string",
"pattern": "^curl\/"
},
"Host": {
"type": "string",
"enum": ["httpbin.org", "httpbin"]
}
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
#### 使用符合架构的请求进行验证
发送带有标头 `Host: httpbin` 的请求,该请求符合架构:
```shell
curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6509ae35-63d1e0fd3934e3f221a95dd8",
"X-Forwarded-Host": "httpbin"
},
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://httpbin/get"
}
```
#### 验证请求是否符合架构
发送不带任何标头的请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您应该收到 `HTTP/1.1 400 Bad Request` 响应,表明请求未能通过验证:
```text
property "Host" validation failed: matches none of the enum value
```
发送具有所需标头但标头值不符合的请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin" -H "User-Agent: cli-mock"
```
您应该收到一个 `HTTP/1.1 400 Bad Request` 响应,显示 `User-Agent` 标头值与预期模式不匹配:
```text
property "User-Agent" validation failed: failed to match pattern "^curl/" with "cli-mock"
```
### 自定义拒绝消息和状态代码
以下示例演示了如何在验证失败时自定义响应状态和消息。
使用 `request-validation` 配置路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "request-validation-route",
"uri": "/get",
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"required": ["Host"],
"properties": {
"Host": {
"type": "string",
"enum": ["httpbin.org", "httpbin"]
}
}
},
"rejected_code": 403,
"rejected_msg": "Request header validation failed."
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送一个在标头中配置错误的 `Host` 的请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin2"
```
您应该收到带有自定义消息的 `HTTP/1.1 403 Forbidden` 响应:
```text
Request header validation failed.
```
### 验证请求主体
以下示例演示如何根据定义的 JSON Schema 验证请求主体。
`request-validation` 插件支持两种媒体类型的验证:
* `application/json`
* `application/x-www-form-urlencoded`
#### 验证 JSON 请求主体
使用 `request-validation` 插件创建路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "request-validation-route",
"uri": "/post",
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"required": ["Content-Type"],
"properties": {
"Content-Type": {
"type": "string",
"pattern": "^application\/json$"
}
}
},
"body_schema": {
"type": "object",
"required": ["required_payload"],
"properties": {
"required_payload": {"type": "string"},
"boolean_payload": {"type": "boolean"},
"array_payload": {
"type": "array",
"minItems": 1,
"items": {
"type": "integer",
"minimum": 200,
"maximum": 599
},
"uniqueItems": true,
"default": [200]
}
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送符合架构的 JSON Schema 的请求以验证:
```shell
curl -i "http://127.0.0.1:9080/post" -X POST \
-H "Content-Type: application/json" \
-d '{"required_payload":"hello", "array_payload":[301]}'
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "{\"array_payload\":[301],\"required_payload\":\"hello\"}",
"files": {},
"form": {},
"headers": {
...
},
"json": {
"array_payload": [
301
],
"required_payload": "hello"
},
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://127.0.0.1/post"
}
```
如果你发送请求时没有指定 `Content-Typeapplication/json`
```shell
curl -i "http://127.0.0.1:9080/post" -X POST \
-d '{"required_payload":"hello,world"}'
```
您应该收到类似于以下内容的 `HTTP/1.1 400 Bad Request` 响应:
```text
property "Content-Type" validation failed: failed to match pattern "^application/json$" with "application/x-www-form-urlencoded"
```
如果你发送的请求没有必需的 JSON 字段 `required_payload`
```shell
curl -i "http://127.0.0.1:9080/post" -X POST \
-H "Content-Type: application/json" \
-d '{}'
```
您应该收到 `HTTP/1.1 400 Bad Request` 响应:
```text
property "required_payload" is required
```
#### 验证 URL 编码的表单主体
使用 `request-validation` 插件创建路由,如下所示:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "request-validation-route",
"uri": "/post",
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"required": ["Content-Type"],
"properties": {
"Content-Type": {
"type": "string",
"pattern": "^application\/x-www-form-urlencoded$"
}
}
},
"body_schema": {
"type": "object",
"required": ["required_payload","enum_payload"],
"properties": {
"required_payload": {"type": "string"},
"enum_payload": {
"type": "string",
"enum": ["enum_string_1", "enum_string_2"],
"default": "enum_string_1"
}
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送带有 URL 编码的表单数据的请求来验证:
```shell
curl -i "http://127.0.0.1:9080/post" -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "required_payload=hello&enum_payload=enum_string_1"
```
您应该收到类似于以下内容的 `HTTP/1.1 400 Bad Request` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"enum_payload": "enum_string_1",
"required_payload": "hello"
},
"headers": {
...
},
"json": null,
"origin": "127.0.0.1, 183.17.233.107",
"url": "http://127.0.0.1/post"
}
```
发送不带 URL 编码字段 `enum_payload` 的请求:
```shell
curl -i "http://127.0.0.1:9080/post" -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "required_payload=hello"
```
您应该收到以下 `HTTP/1.1 400 Bad Request`
```text
property "enum_payload" is required
```
## 附录JSON 模式
以下部分提供了样板 JSON 模式,供您调整、组合和使用此插件。有关完整参考,请参阅 [JSON 模式规范](https://json-schema.org/specification)
### 枚举值
```json
{
"body_schema": {
"type": "object",
"required": ["enum_payload"],
"properties": {
"enum_payload": {
"type": "string",
"enum": ["enum_string_1", "enum_string_2"],
"default": "enum_string_1"
}
}
}
}
```
### 布尔值
```json
{
"body_schema": {
"type": "object",
"required": ["bool_payload"],
"properties": {
"bool_payload": {
"type": "boolean",
"default": true
}
}
}
}
```
### 数值
```json
{
"body_schema": {
"type": "object",
"required": ["integer_payload"],
"properties": {
"integer_payload": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
}
}
}
```
### 字符串
```json
{
"body_schema": {
"type": "object",
"required": ["string_payload"],
"properties": {
"string_payload": {
"type": "string",
"minLength": 1,
"maxLength": 32
}
}
}
}
```
### 字符串的正则表达式
```json
{
"body_schema": {
"type": "object",
"required": ["regex_payload"],
"properties": {
"regex_payload": {
"type": "string",
"minLength": 1,
"maxLength": 32,
"pattern": "[[^[a-zA-Z0-9_]+$]]"
}
}
}
}
```
### 数组
```json
{
"body_schema": {
"type": "object",
"required": ["array_payload"],
"properties": {
"array_payload": {
"type": "array",
"minItems": 1,
"items": {
"type": "integer",
"minimum": 200,
"maximum": 599
},
"uniqueItems": true,
"default": [200, 302]
}
}
}
}
```

View File

@@ -0,0 +1,313 @@
---
title: response-rewrite
keywords:
- Apache APISIX
- API 网关
- Plugin
- Response Rewrite
- response-rewrite
description: response-rewrite 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用该插件,您可以修改 HTTP 状态代码、请求标头、响应正文等。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/response-rewrite" />
</head>
## 描述
`response-rewrite` 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用此插件,您可以修改 HTTP 状态代码、请求标头、响应正文等。
例如,您可以使用此插件来:
- 通过设置 `Access-Control-Allow-*` 标头来支持 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
- 通过设置 HTTP 状态代码和 `Location` 标头来指示重定向。
:::tip
如果你仅需要重定向功能,建议使用 [redirect](redirect.md) 插件。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|-----------------|---------|--------|--------|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| status_code | integer | 否 | | [200, 598] | 修改上游返回状态码,默认保留原始响应代码。 |
| body | string | 否 | | | 修改上游返回的 `body` 内容如果设置了新内容header 里面的 `Content-Length` 字段也会被去掉。 |
| body_base64 | boolean | 否 | false | | 如果为 true则在发送到客户端之前解码`body` 中配置的响应主体,这对于图像和 protobuf 解码很有用。请注意,此配置不能用于解码上游响应。 |
| headers | object | 否 | | | 按照 `add``remove``set` 的顺序执行的操作。 |
| headers.add | array[string] | 否 | | | 要附加到请求的标头。如果请求中已经存在标头,则会附加标头值。标头值可以设置为常量,也可以设置为一个或多个 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。 |
| headers.set | object | 否 | | |要设置到请求的标头。如果请求中已经存在标头,则会覆盖标头值。标头值可以设置为常量,也可以设置为一个或多个[Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。 |
| headers.remove | array[string] | 否 | | | 要从请求中删除的标头。 |
| vars | array[array] | 否 | | | 以 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 的形式包含一个或多个匹配条件的数组。 |
| filters | array[object] | 否 | | | 通过将一个指定字符串替换为另一个指定字符串来修改响应主体的过滤器列表。不应与 `body` 一起配置。 |
| filters.regex | string | True | | | 用于匹配响应主体的 RegEx 模式。 |
| filters.scope | string | 否 | "once" | ["once","global"] | 替换范围。`once` 替换第一个匹配的实例,`global` 全局替换。 |
| filters.replace | string | True | | | 要替换的内容。 |
| filters.options | string | 否 | "jo" | | 用于控制如何执行匹配操作的 RegEx 选项。请参阅[Lua NGINX 模块](https://github.com/openresty/lua-nginx-module#ngxrematch)以了解可用选项。|
## 示例
以下示例演示了如何在不同场景中在路由上配置 `response-rewrite`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 重写标头和正文
以下示例演示了如何添加响应正文和标头,仅适用于具有 `200` HTTP 状态代码的响应。
创建一个带有 `response-rewrite` 插件的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins": {
"response-rewrite": {
"body": "{\"code\":\"ok\",\"message\":\"new json body\"}",
"headers": {
"set": {
"X-Server-id": 3,
"X-Server-status": "on",
"X-Server-balancer-addr": "$balancer_ip:$balancer_port"
}
},
"vars": [
[ "status","==",200 ]
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl -i "http://127.0.0.1:9080/headers"
```
您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```text
...
X-Server-id: 3
X-Server-status: on
X-Server-balancer-addr: 50.237.103.220:80
{"code":"ok","message":"new json body"}
```
### 使用 RegEx 过滤器重写标头
以下示例演示如何使用 RegEx 过滤器匹配替换响应中的 `X-Amzn-Trace-Id`
创建一个带有 `response-rewrite` 插件的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins":{
"response-rewrite":{
"filters":[
{
"regex":"X-Amzn-Trace-Id",
"scope":"global",
"replace":"X-Amzn-Trace-Id-Replace"
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl -i "http://127.0.0.1:9080/headers"
```
您应该会看到类似以下内容的响应:
```text
{
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id-Replace": "Root=1-6500095d-1041b05e2ba9c6b37232dbc7",
"X-Forwarded-Host": "127.0.0.1"
}
}
```
### 从 Base64 解码正文
以下示例演示如何从 Base64 格式解码正文。
创建一个带有 `response-rewrite` 插件的路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/get",
"plugins":{
"response-rewrite": {
"body": "SGVsbG8gV29ybGQ=",
"body_base64": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
发送请求以验证:
```shell
curl "http://127.0.0.1:9080/get"
```
您应该看到以下响应:
```text
Hello World
```
### 重写响应及其与执行阶段的联系
以下示例通过使用 `key-auth` 插件配置插件,演示了 `response-rewrite` 插件与 [执行阶段](/apisix/key-concepts/plugins#plugins-execution-lifecycle) 之间的联系,并查看在未经身份验证的请求的情况下,响应仍如何重写为 `200 OK`
创建消费者 `jack`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jack"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
```
创建一个带有 `key-auth` 的路由,并配置 `response-rewrite` 来重写响应状态码和主体:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "response-rewrite-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"response-rewrite": {
"status_code": 200,
"body": "{\"code\": 200, \"msg\": \"success\"}"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
使用有效密钥向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/get" -H 'apikey: jack-key'
```
您应该收到以下 `HTTP/1.1 200 OK` 响应:
```text
{"code": 200, "msg": "success"}
```
向路由发送一个没有任何键的请求:
```shell
curl -i "http://127.0.0.1:9080/get"
```
您仍应收到相同的 `HTTP/1.1 200 OK` 响应,而不是来自 `key-auth` 插件的 `HTTP/1.1 401 Unauthorized`。这表明 `response-rewrite` 插件仍在重写响应。
这是因为 `response-rewrite` 插件的 **header_filter** **body_filter** 阶段逻辑将在 [`ngx.exit`](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) 之后在其他插件的 **access** **rewrite** 阶段继续运行。
下表总结了 `ngx.exit` 对执行阶段的影响。
| 阶段 | rewrite | access | header_filter | body_filter |
|---------------|----------|----------|---------------|-------------|
| **rewrite** | ngx.exit | | | |
| **access** | × | ngx.exit | | |
| **header_filter** | ✓ | ✓ | ngx.exit | |
| **body_filter** | ✓ | ✓ | × | ngx.exit |
例如,如果 `ngx.exit` 发生在 **rewrite** 阶段,它将中断 **access** 阶段的执行,但不会干扰 **header_filter** **body_filter** 阶段。

View File

@@ -0,0 +1,225 @@
---
title: rocketmq-logger
keywords:
- APISIX
- API 网关
- Plugin
- RocketMQ
description: API 网关 Apache APISIX 的 rocketmq-logger 插件用于将日志作为 JSON 对象推送到 Apache RocketMQ 集群中。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`rocketmq-logger` 插件可以将日志以 JSON 的形式推送给外部 RocketMQ 集群。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | ------- | ------ | ---------------- | ------------- ------- | ------------------------------------------------ |
| nameserver_list | object | 是 | | | RocketMQ 的 nameserver 列表。 |
| topic | string | 是 | | | 要推送的 topic 名称。 |
| key | string | 否 | | | 发送消息的 keys。 |
| tag | string | 否 | | | 发送消息的 tags。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| timeout | integer | 否 | 3 | [1,...] | 发送数据的超时时间。 |
| use_tls | boolean | 否 | false | | 当设置为 `true` 时,开启 TLS 加密。 |
| access_key | string | 否 | "" | | ACL 认证的 Access key空字符串表示不开启 ACL。 |
| secret_key | string | 否 | "" | | ACL 认证的 Secret key。 |
| name | string | 否 | "rocketmq logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| meta_format | enum | 否 | "default" | ["default""origin"] | `default`:获取请求信息以默认的 JSON 编码方式。`origin`:获取请求信息以 HTTP 原始请求方式。更多信息,请参考 [meta_format](#meta_format-示例)。|
| include_req_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含请求体。**注意**:如果请求体无法完全存放在内存中,由于 NGINX 的限制APISIX 无法将它记录下来。|
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时进行过滤请求体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录请求体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
| include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
注意schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
:::tip 提示
数据首先写入缓冲区。当缓冲区超过 `batch_max_size``buffer_duration` 设置的值时,则会将数据发送到 RocketMQ 服务器并刷新缓冲区。
如果发送成功,则返回 `true`。如果出现错误,则返回 `nil`,并带有描述错误的字符串 `buffer overflow`
:::
### meta_format 示例
- default:
```json
{
"upstream": "127.0.0.1:1980",
"start_time": 1619414294760,
"client_ip": "127.0.0.1",
"service_id": "",
"route_id": "1",
"request": {
"querystring": {
"ab": "cd"
},
"size": 90,
"uri": "/hello?ab=cd",
"url": "http://localhost:1984/hello?ab=cd",
"headers": {
"host": "localhost",
"content-length": "6",
"connection": "close"
},
"method": "GET"
},
"response": {
"headers": {
"connection": "close",
"content-type": "text/plain; charset=utf-8",
"date": "Mon, 26 Apr 2021 05:18:14 GMT",
"server": "APISIX/2.5",
"transfer-encoding": "chunked"
},
"size": 190,
"status": 200
},
"server": {
"hostname": "localhost",
"version": "2.5"
},
"latency": 0
}
```
- origin:
```http
GET /hello?ab=cd HTTP/1.1
host: localhost
content-length: 6
connection: close
abcdef
```
## 插件元数据设置
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|------------|--------|-----|-------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| log_format | object | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::note 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `rocketmq-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/rocketmq-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
在日志收集处,将得到类似下面的日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 启用插件
你可以通过如下命令在指定路由上启用 `rocketmq-logger` 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"rocketmq-logger": {
"nameserver_list" : [ "127.0.0.1:9876" ],
"topic" : "test2",
"batch_max_size": 1,
"name": "rocketmq logger"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
该插件还支持一次推送到多个 `nameserver`,示例如下:
```json
[
"127.0.0.1:9876",
"127.0.0.2:9876"
]
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,118 @@
---
title: server-info
keywords:
- Apache APISIX
- API 网关
- Plugin
- Server info
- server-info
description: 本文介绍了关于 Apache APISIX `server-info` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`server-info` 插件可以定期将服务基本信息上报至 etcd。
:::warning
`server-info` 插件已弃用,将在未来的版本中被移除。更多关于弃用和移除计划的信息,请参考[这个讨论](https://github.com/apache/apisix/discussions/12298)
:::
服务信息中每一项的含义如下:
| 名称 | 类型 | 描述 |
| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
| boot_time | integer | APISIX 服务实例的启动时间UNIX 时间戳),如果对 APISIX 进行热更新操作,该值将被重置。普通的 reload 操作不会影响该值。 |
| id | string | APISIX 服务实例 id。 |
| etcd_version | string | etcd 集群的版本信息,如果 APISIX 和 etcd 集群之间存在网络分区,该值将设置为 `"unknown"`。 |
| version | string | APISIX 版本信息。 |
| hostname | string | 部署 APISIX 的主机或 Pod 的主机名信息。 |
## 属性
无。
## 插件接口
该插件在 [Control API](../control-api.md) 下暴露了一个 API 接口 `/v1/server_info`
## 启用插件
该插件默认是禁用状态,你可以在配置文件(`./conf/config.yaml`)中添加如下配置启用 `server-info` 插件。
```yaml title="conf/config.yaml"
plugins: # plugin list
- ...
- server-info
```
## 自定义服务信息上报配置
我们可以在 `./conf/config.yaml` 文件的 `plugin_attr` 部分修改上报配置。
下表是可以自定义配置的参数:
| 名称 | 类型 | 默认值 | 描述 |
| --------------- | ------- | ------ | --------------------------------------------------------------- |
| report_ttl | integer | 36 | etcd 中服务信息保存的 TTL单位最大值86400最小值3。|
以下是示例是通过修改配置文件(`conf/config.yaml`)中的 `plugin_attr` 部分将 `report_ttl` 设置为 1 分钟:
```yaml title="conf/config.yaml"
plugin_attr:
server-info:
report_ttl: 60
```
## 测试插件
在启用 `server-info` 插件后,可以通过插件的 Control API 来访问到这些数据:
```shell
curl http://127.0.0.1:9090/v1/server_info -s | jq .
```
```JSON
{
"etcd_version": "3.5.0",
"id": "b7ce1c5c-b1aa-4df7-888a-cbe403f3e948",
"hostname": "fedora32",
"version": "2.1",
"boot_time": 1608522102
}
```
:::tip
你可以通过 [APISIX Dashboard](/docs/dashboard/USER_GUIDE) 查看服务信息报告。
:::
## 删除插件
如果你想禁用插件,可以将 `server-info` 从配置文件中的插件列表删除,重新加载 APISIX 后即可生效。
```yaml title="conf/config.yaml"
plugins: # plugin list
- ...
```

View File

@@ -0,0 +1,147 @@
---
title: serverless
keywords:
- Apache APISIX
- API 网关
- Plugin
- Serverless
description: 本文介绍了关于 API 网关 Apache APISIX serverless-pre-function 和 serverless-post-function 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
APISIX 有两个 `serverless` 插件:`serverless-pre-function``serverless-post-function`
`serverless-pre-function` 插件会在指定阶段开始时运行,`serverless-post-function` 插件会在指定阶段结束时运行。这两个插件使用相同的属性。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------- | ------------- | ------- | ---------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| phase | string | 否 | ["access"] | ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"] | 执行 serverless 函数的阶段。 |
| functions | array[string] | 是 | | | 指定运行的函数列表。该属性可以包含一个函数,也可以是多个函数,按照先后顺序执行。 |
:::info 重要
此处仅接受函数,不接受其他类型的 Lua 代码。
比如匿名函数是合法的:
```lua
return function()
ngx.log(ngx.ERR, 'one')
end
```
闭包也是合法的:
```lua
local count = 1
return function()
count = count + 1
ngx.say(count)
end
```
但不是函数类型的代码就是非法的:
```lua
local count = 1
ngx.say(count)
```
:::
:::note 注意
`v2.6` 版本开始,`conf``ctx` 作为前两个参数传递给 `serverless` 函数。
`v2.12.0` 版本之前,`before_proxy` 阶段曾被称作 `balancer`。考虑到这一方法是在 `access` 阶段之后、请求到上游之前运行,并且与 `balancer` 没有关联,因此已经更新为 `before_proxy`
:::
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions" : ["return function() ngx.log(ngx.ERR, \"serverless pre function\"); end"]
},
"serverless-post-function": {
"phase": "rewrite",
"functions" : ["return function(conf, ctx) ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); end"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/index.html
```
如果你在 `./logs/error.log` 中发现 `serverless pre function``match uri /index.html` 两个 error 级别的日志,表示指定的函数已经生效。
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,343 @@
---
title: skywalking-logger
keywords:
- Apache APISIX
- API 网关
- Plugin
- SkyWalking
description: skywalking-logger 将请求和响应日志作为 JSON 对象批量推送到 SkyWalking OAP 服务器,并支持日志格式的自定义。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/skywalking-logger" />
</head>
## 描述
`skywalking-logger` 插件将请求和响应日志作为 JSON 对象批量推送到 SkyWalking OAP 服务器,并支持日志格式的自定义。
如果存在现有的跟踪上下文,它会自动设置跟踪日志关联并依赖于 [SkyWalking 跨进程传播标头协议](https://skywalking.apache.org/docs/main/next/en/api/x-process-propagation-headers-v3/)
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | ------- | ------ | -------------------- | ------------- | ---------------------------------------------------------------- |
| endpoint_addr | string | 是 | | | SkyWalking OAP 服务器的 URI。 |
| service_name | string | 否 |"APISIX" | | SkyWalking 服务名称。 |
| service_instance_name | string | 否 |"APISIX Instance Name"| | SkyWalking 服务的实例名称。当设置为 `$hostname` 会直接获取本地主机名。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| timeout | integer | 否 | 3 | [1,...] | 发送请求后保持连接活动的时间。 |
| name | string | 否 | "skywalking logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| include_req_body | boolean | 否 | false |如果为 true则将请求主体包含在日志中。请注意如果请求主体太大而无法保存在内存中则由于 NGINX 的限制而无法记录。|
| include_req_body_expr | array[array] | 否 | | 一个或多个条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。在 `include_req_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录请求主体。|
| include_resp_body | boolean | 否 | false | 如果为 true则将响应主体包含在日志中。|
| include_resp_body_expr | array[array] | 否 | | 一个或多个条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。在 `include_resp_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录响应主体。|
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
## 元数据
您还可以通过配置插件元数据来设置日志的格式。可用的配置如下:
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | ------- | ------ | -------------------- | ------------- | ---------------------------------------------------------------- |
| log_format | object | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
## 示例
以下示例演示了如何为不同场景配置 `skywalking-logger` 插件。
要按照示例操作,请按照 [Skywalking 的文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/) 使用 Docker Compose 启动存储、OAP 和 Booster UI。设置完成后OAP 服务器应在 `12800` 上监听,并且您应该能够通过 [http://localhost:8080](http://localhost:8080) 访问 UI。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 以默认日志格式记录请求
以下示例演示了如何在路由上配置 `skywalking-logger` 插件,以记录到达路由的请求信息。
使用 `skywalking-logger` 插件创建路由,并使用 OAP 服务器 URI 配置插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-logger-route",
"uri": "/anything",
"plugins": {
"skywalking-logger": {
"endpoint_addr": "http://192.168.2.103:12800"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
[Skywalking UI](http://localhost:8080) 中,导航至 __General Service__ > __Services__。您应该会看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的日志条目:
```json
{
"upstream_latency": 674,
"request": {
"method": "GET",
"headers": {
"user-agent": "curl/8.6.0",
"host": "127.0.0.1:9080",
"accept": "*/*"
},
"url": "http://127.0.0.1:9080/anything",
"size": 85,
"querystring": {},
"uri": "/anything"
},
"client_ip": "192.168.65.1",
"route_id": "skywalking-logger-route",
"start_time": 1736945107345,
"upstream": "3.210.94.60:80",
"server": {
"version": "3.11.0",
"hostname": "7edbcebe8eb3"
},
"service_id": "",
"response": {
"size": 619,
"status": 200,
"headers": {
"content-type": "application/json",
"date": "Thu, 16 Jan 2025 12:45:08 GMT",
"server": "APISIX/3.11.0",
"access-control-allow-origin": "*",
"connection": "close",
"access-control-allow-credentials": "true",
"content-length": "391"
}
},
"latency": 764.9998664856,
"apisix_latency": 90.999866485596
}
```
### 使用插件元数据记录请求和响应标头
以下示例演示了如何使用插件元数据和内置变量自定义日志格式,以记录来自请求和响应的特定标头。
在 APISIX 中,插件元数据用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并需要对其元数据字段进行通用更新时,它很有用。
首先,使用 `skywalking-logger` 插件创建路由,并使用您的 OAP 服务器 URI 配置插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-logger-route",
"uri": "/anything",
"plugins": {
"skywalking-logger": {
"endpoint_addr": "http://192.168.2.103:12800"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
接下来,配置 `skywalking-logger` 的插件元数据,以记录自定义请求头 `env` 和响应头 `Content-Type`:
```shell
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/skywalking-logger" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr",
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'
```
使用 `env` 标头向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -H "env: dev"
```
您应该收到 `HTTP/1.1 200 OK` 响应。在 [Skywalking UI](http://localhost:8080) 中,导航至 __General Service__ > __Services__。您应该会看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的日志条目:
```json
[
{
"route_id": "skywalking-logger-route",
"client_ip": "192.168.65.1",
"@timestamp": "2025-01-16T12:51:53+00:00",
"host": "127.0.0.1",
"env": "dev",
"resp_content_type": "application/json"
}
]
```
### 有条件地记录请求主体
以下示例演示了如何有条件地记录请求主体。
使用 `skywalking-logger` 插件创建一个路由,仅当 URL 查询字符串 `log_body``yes` 时才包含请求主体:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-logger-route",
"uri": "/anything",
"plugins": {
"skywalking-logger": {
"endpoint_addr": "http://192.168.2.103:12800",
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
使用满足以下条件的 URL 查询字符串向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'
```
您应该收到 `HTTP/1.1 200 OK` 响应。在 [Skywalking UI](http://localhost:8080) 中,导航到 __General Service__ > __Services__。您应该看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的日志条目,并记录了请求正文:
```json
[
{
"request": {
"url": "http://127.0.0.1:9080/anything?log_body=yes",
"querystring": {
"log_body": "yes"
},
"uri": "/anything?log_body=yes",
...,
"body": "{\"env\": \"dev\"}",
},
...
}
]
```
向路由发送一个没有任何 URL 查询字符串的请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'
```
您不应该观察到没有请求正文的日志条目。
:::info
如果您除了将 `include_req_body``include_resp_body` 设置为 `true` 之外还自定义了 `log_format`,则插件不会在日志中包含正文。
作为一种解决方法,您可以在日志格式中使用 NGINX 变量 `$request_body`,例如:
```json
{
"skywalking-logger": {
...,
"log_format": {"body": "$request_body"}
}
}
```
:::
### 将跟踪与日志关联
以下示例演示了如何在路由上配置 `skywalking-logger` 插件,以记录到达路由的请求信息。
使用 `skywalking-logger` 插件创建路由,并使用 OAP 服务器 URI 配置插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-logger-route",
"uri": "/anything",
"plugins": {
"skywalking": {
"sample_ratio": 1
},
"skywalking-logger": {
"endpoint_addr": "http://192.168.2.103:12800"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
生成几个对路由的请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
[Skywalking UI](http://localhost:8080) 中,导航到 __General Service__ > __Services__。您应该会看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的跟踪,您可以在其中查看相关日志:
![trace context](https://static.apiseven.com/uploads/2025/01/16/soUpXm6b_trace-view-logs.png)
![associated log](https://static.apiseven.com/uploads/2025/01/16/XD934LvU_associated-logs.png)

View File

@@ -0,0 +1,180 @@
---
title: skywalking
keywords:
- Apache APISIX
- API 网关
- Plugin
- SkyWalking
description: skywalking 插件支持与 Apache SkyWalking 集成以进行请求跟踪。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/skywalking" />
</head>
## 描述
`skywalking` 插件支持与 [Apache SkyWalking](https://skywalking.apache.org) 集成以进行请求跟踪。
SkyWalking 使用其原生的 Nginx Lua 跟踪器从服务和 URI 角度提供跟踪、拓扑分析和指标。APISIX 支持 HTTP 协议与 SkyWalking 服务器交互。
服务端目前支持 HTTP 和 gRPC 两种协议,在 APISIX 中目前只支持 HTTP 协议。
## 静态配置
默认情况下,插件的服务名称和端点地址已在[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中预先配置。
要自定义这些值,请将相应的配置添加到 `config.yaml`。例如:
```yaml
plugin_attr:
skywalking:
report_interval: 3 # 上报间隔时间(秒)。
service_name: APISIX # SkyWalking 记者的服务名称。
service_instance_name: "APISIX Instance Name" # SkyWalking 记者的服务实例名称。
# 设置为 $hostname 可获取本地主机名。
endpoint_addr: http://127.0.0.1:12800 # SkyWalking HTTP 端点。
```
重新加载 APISIX 以使更改生效。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------ | ------ | ------ | ------ | ------------ | ----------------------------------------------------- |
| sample_ratio | number | 是 | 1 | [0.00001, 1] | 请求采样频率。将采样率设置为 `1` 表示对所有请求进行采样。 |
## 示例
要遵循示例,请按照 [Skywalking 的文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/) 使用 Docker Compose 启动存储、OAP 和 Booster UI。设置完成后OAP 服务器应监听 `12800`,您应该能够通过 [http://localhost:8080](http://localhost:8080) 访问 UI。
更新 APISIX 配置文件以启用 `skywalking` 插件(默认情况下处于禁用状态),并更新端点地址:
```yaml title="config.yaml"
plugins:
- skywalking
- ...
plugin_attr:
skywalking:
report_interval: 3
service_name: APISIX
service_instance_name: APISIX Instance
endpoint_addr: http://192.168.2.103:12800
```
重新加载 APISIX 以使配置更改生效。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 跟踪所有请求
以下示例演示了如何跟踪通过路由的所有请求。
使用 `skywalking` 创建路由,并将采样率配置为 1 以跟踪所有请求:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-route",
"uri": "/anything",
"plugins": {
"skywalking": {
"sample_ratio": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
向路由发送几个请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到 `HTTP/1.1 200 OK` 响应。
在 [Skywalking UI](http://localhost:8080) 中,导航到 __General Service__ > __Services__。您应该看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的跟踪:
![SkyWalking APISIX 跟踪](https://static.apiseven.com/uploads/2025/01/15/UdwiO8NJ_skywalking-traces.png)
### 将跟踪与日志关联
以下示例演示了如何在路由上配置 `skywalking-logger` 插件,以记录到达路由的请求信息。
使用 `skywalking-logger` 插件创建路由,并使用你的 OAP 服务器 URI 配置该插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "skywalking-logger-route",
"uri": "/anything",
"plugins": {
"skywalking": {
"sample_ratio": 1
},
"skywalking-logger": {
"endpoint_addr": "http://192.168.2.103:12800"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
```
生成几个对路由的请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该会收到 `HTTP/1.1 200 OK` 响应。
在 [Skywalking UI](http://localhost:8080) 中,导航到 __General Service__ > __Services__。您应该会看到一个名为 `APISIX` 的服务,其中包含与您的请求相对应的跟踪,您可以在其中查看相关日志:
![trace context](https://static.apiseven.com/uploads/2025/01/16/soUpXm6b_trace-view-logs.png)
![associated log](https://static.apiseven.com/uploads/2025/01/16/XD934LvU_associated-logs.png)

View File

@@ -0,0 +1,180 @@
---
title: sls-logger
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`sls-logger` 是使用 [RF5424](https://tools.ietf.org/html/rfc5424) 标准将日志数据以 JSON 格式发送到 [阿里云日志服务](https://help.aliyun.com/document_detail/112903.html?spm=a2c4g.11186623.6.763.21321b47wcwt1u)
该插件提供了将 Log Data 作为批处理推送到阿里云日志服务器的功能。如果您没有收到日志数据,请放心一些时间,它会在我们的批处理处理器中的计时器功能到期后自动发送日志。
有关 Apache APISIX 中 Batch-Processor 的更多信息,请参考:
[Batch-Processor](../batch-processor.md)
## 属性
| 属性名称 | 必选项 | 描述 |
|--------- |--------|-----------|
| host | 必要的 | TCP 服务的 IP 地址或主机名,请参考:[阿里云日志服务列表](https://help.aliyun.com/document_detail/29008.html?spm=a2c4g.11186623.2.14.49301b4793uX0z#reference-wgx-pwq-zdb),建议配置 IP 取代配置域名。|
| port | 必要的 | 目标端口,阿里云日志服务默认端口为 10009。|
| timeout | 可选的 | 发送数据超时间。|
| log_format | 可选的 | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| project | 必要的 | 日志服务 Project 名称,请提前在阿里云日志服务中创建 Project。|
| logstore | 必须的 | 日志服务 Logstore 名称,请提前在阿里云日志服务中创建 Logstore。|
| access_key_id | 必须的 | AccessKey ID。建议使用阿里云子账号 AK详情请参见 [授权](https://help.aliyun.com/document_detail/47664.html?spm=a2c4g.11186623.2.15.49301b47lfvxXP#task-xsk-ttc-ry)。|
| access_key_secret | 必须的 | AccessKey Secret。建议使用阿里云子账号 AK详情请参见 [授权](https://help.aliyun.com/document_detail/47664.html?spm=a2c4g.11186623.2.15.49301b47lfvxXP#task-xsk-ttc-ry)。|
| include_req_body | 可选的 | 是否包含请求体。|
| include_req_body_expr | 可选的 | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | 可选的 | 当设置为 `true` 时,日志中将包含响应体。 |
| include_resp_body_expr | 可选的 | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
|name| 可选的 | 批处理名字。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。|
注意schema 中还定义了 `encrypt_fields = {"access_key_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
本插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。
### 默认日志格式示例
```json
{
"route_conf": {
"host": "100.100.99.135",
"buffer_duration": 60,
"timeout": 30000,
"include_req_body": false,
"logstore": "your_logstore",
"log_format": {
"vip": "$remote_addr"
},
"project": "your_project",
"inactive_timeout": 5,
"access_key_id": "your_access_key_id",
"access_key_secret": "your_access_key_secret",
"batch_max_size": 1000,
"max_retry_count": 0,
"retry_delay": 1,
"port": 10009,
"name": "sls-logger"
},
"data": "<46>1 2024-01-06T03:29:56.457Z localhost apisix 28063 - [logservice project=\"your_project\" logstore=\"your_logstore\" access-key-id=\"your_access_key_id\" access-key-secret=\"your_access_key_secret\"] {\"vip\":\"127.0.0.1\",\"route_id\":\"1\"}\n"
}
```
## 插件元数据设置
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 可选 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[Nginx 内置变量](http://nginx.org/en/docs/varindex.html)。特别的,**该设置是全局生效的**,意味着指定 log_format 后,将对所有绑定 sls-logger 的 Route 或 Service 生效。 |
### 设置日志格式示例
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/sls-logger -H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
在日志收集处,将得到类似下面的日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 如何开启
1. 下面例子展示了如何为指定路由开启 `sls-logger` 插件的。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/5 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"sls-logger": {
"host": "100.100.99.135",
"port": 10009,
"project": "your_project",
"logstore": "your_logstore",
"access_key_id": "your_access_key_id",
"access_key_secret": "your_access_key_secret",
"timeout": 30000
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
```
注释:这里的 100.100.99.135 是阿里云华北 3 内外地址。
```
## 测试插件
* 成功的情况:
```shell
$ curl -i http://127.0.0.1:9080/hello
HTTP/1.1 200 OK
...
hello, world
```
* 查看阿里云日志服务上传记录
![sls logger view](../../../assets/images/plugin/sls-logger-1.png "阿里云日志服务预览")
## 删除插件
想要禁用“sls-logger”插件是非常简单的将对应的插件配置从 json 配置删除,就会立即生效,不需要重新启动服务:
```shell
$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,218 @@
---
title: splunk-hec-logging
keywords:
- Apache APISIX
- API 网关
- 插件
- Splunk
- 日志
description: API 网关 Apache APISIX 的 splunk-hec-logging 插件可用于将请求日志转发到 Splunk HTTP 事件收集器HEC中进行分析和存储。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`splunk-hec-logging` 插件可用于将请求日志转发到 Splunk HTTP 事件收集器HEC中进行分析和存储。
启用该插件后APISIX 将在 `Log Phase` 获取请求上下文信息,并将其序列化为 [Splunk Event Data 格式](https://docs.splunk.com/Documentation/Splunk/latest/Data/FormateventsforHTTPEventCollector#Event_metadata) 后提交到批处理队列中,当触发批处理队列每批次最大处理容量或刷新缓冲区的最大时间时会将队列中的数据提交到 `Splunk HEC` 中。
## 属性
| 名称 | 必选项 | 默认值 | 描述 |
| ------------------ | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| endpoint | 是 | | Splunk HEC 端点配置信息。 |
| endpoint.uri | 是 | | Splunk HEC 事件收集 API。 |
| endpoint.token | 是 | | Splunk HEC 身份令牌。 |
| endpoint.channel | 否 | | Splunk HEC 发送渠道标识,更多信息请参考 [About HTTP Event Collector Indexer Acknowledgment](https://docs.splunk.com/Documentation/Splunk/8.2.3/Data/AboutHECIDXAck)。 |
| endpoint.timeout | 否 | 10 | Splunk HEC 数据提交超时时间(以秒为单位)。 |
| ssl_verify | 否 | true | 当设置为 `true` 时,启用 `SSL` 验证。 |
| log_format | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
本插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免该插件频繁地提交数据。默认情况下每 `5` 秒钟或队列中的数据达到 `1000` 条时,批处理器会自动提交数据,如需了解更多信息或自定义配置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"sourcetype": "_json",
"time": 1704513555.392,
"event": {
"upstream": "127.0.0.1:1980",
"request_url": "http://localhost:1984/hello",
"request_query": {},
"request_size": 59,
"response_headers": {
"content-length": "12",
"server": "APISIX/3.7.0",
"content-type": "text/plain",
"connection": "close"
},
"response_status": 200,
"response_size": 118,
"latency": 108.00004005432,
"request_method": "GET",
"request_headers": {
"connection": "close",
"host": "localhost"
}
},
"source": "apache-apisix-splunk-hec-logging",
"host": "localhost"
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `splunk-hec-logging` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/splunk-hec-logging \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```json
[{"time":1673976669.269,"source":"apache-apisix-splunk-hec-logging","event":{"host":"localhost","client_ip":"127.0.0.1","@timestamp":"2023-01-09T14:47:25+08:00","route_id":"1"},"host":"DESKTOP-2022Q8F-wsl","sourcetype":"_json"}]
```
## 启用插件
以下示例展示了如何在指定路由上启用该插件:
**完整配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins":{
"splunk-hec-logging":{
"endpoint":{
"uri":"http://127.0.0.1:8088/services/collector",
"token":"BD274822-96AA-4DA6-90EC-18940FB2414C",
"channel":"FE0ECFAD-13D5-401B-847D-77833BD77131",
"timeout":60
},
"buffer_duration":60,
"max_retry_count":0,
"retry_delay":1,
"inactive_timeout":2,
"batch_max_size":10
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"127.0.0.1:1980":1
}
},
"uri":"/splunk.do"
}'
```
**最小化配置**
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins":{
"splunk-hec-logging":{
"endpoint":{
"uri":"http://127.0.0.1:8088/services/collector",
"token":"BD274822-96AA-4DA6-90EC-18940FB2414C"
}
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"127.0.0.1:1980":1
}
},
"uri":"/splunk.do"
}'
```
## 测试插件
你可以通过以下命令向 APISIX 发出请求:
```shell
curl -i http://127.0.0.1:9080/splunk.do?q=hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
访问成功后,你可以登录 Splunk 控制台检索查看日志:
![splunk hec search view](../../../assets/images/plugin/splunk-hec-admin-cn.png)
## 删除插件
当你需要删除该插件时,可以通过如下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,144 @@
---
title: syslog
keywords:
- APISIX
- API 网关
- Plugin
- syslog
description: API 网关 Apache APISIX syslog 插件可用于将日志推送到 Syslog 服务器。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`syslog` 插件可用于将日志推送到 Syslog 服务器。
该插件还实现了将日志数据以 JSON 格式发送到 Syslog 服务的能力。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| host | string | 是 | | | IP 地址或主机名。 |
| port | integer | 是 | | | 目标上游端口。 |
| name | string | 否 | "sys logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| timeout | integer | 否 | 3000 | [1, ...] | 上游发送数据超时(以毫秒为单位)。 |
| tls | boolean | 否 | false | | 当设置为 `true` 时执行 SSL 验证。 |
| flush_limit | integer | 否 | 4096 | [1, ...] | 如果缓冲的消息的大小加上当前消息的大小达到(> =)此限制(以字节为单位),则缓冲的日志消息将被写入日志服务器,默认为 40964KB。 |
| drop_limit | integer | 否 | 1048576 | | 如果缓冲的消息的大小加上当前消息的大小大于此限制(以字节为单位),则由于缓冲区大小有限,当前的日志消息将被丢弃,默认为 10485761MB。 |
| sock_type | string | 否 | "tcp" | ["tcp","udp"] | 用于传输层的 IP 协议类型。 |
| max_retry_count | integer | 否 | | [1, ...] | 连接到日志服务器失败或将日志消息发送到日志服务器失败后的最大重试次数。 |
| retry_delay | integer | 否 | | [0, ...] | 重试连接到日志服务器或重试向日志服务器发送日志消息之前的时间延迟(以毫秒为单位)。 |
| pool_size | integer | 否 | 5 | [5, ...] | `sockkeepalive` 使用的 Keepalive 池大小。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| include_req_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时包括请求体。 |
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式示例
```text
"<46>1 2024-01-06T02:30:59.145Z 127.0.0.1 apisix 82324 - - {\"response\":{\"status\":200,\"size\":141,\"headers\":{\"content-type\":\"text/plain\",\"server\":\"APISIX/3.7.0\",\"transfer-encoding\":\"chunked\",\"connection\":\"close\"}},\"route_id\":\"1\",\"server\":{\"hostname\":\"baiyundeMacBook-Pro.local\",\"version\":\"3.7.0\"},\"request\":{\"uri\":\"/opentracing\",\"url\":\"http://127.0.0.1:1984/opentracing\",\"querystring\":{},\"method\":\"GET\",\"size\":155,\"headers\":{\"content-type\":\"application/x-www-form-urlencoded\",\"host\":\"127.0.0.1:1984\",\"user-agent\":\"lua-resty-http/0.16.1 (Lua) ngx_lua/10025\"}},\"upstream\":\"127.0.0.1:1982\",\"apisix_latency\":100.99999809265,\"service_id\":\"\",\"upstream_latency\":1,\"start_time\":1704508259044,\"client_ip\":\"127.0.0.1\",\"latency\":101.99999809265}\n"
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
|------------|--------|-----|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| log_format | object | 否 | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 重要
该设置全局生效。如果指定了 `log_format`,则所有绑定 `syslog` 的路由或服务都将使用该日志格式。
:::
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"syslog": {
"host" : "127.0.0.1",
"port" : 5044,
"flush_limit" : 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
现在你可以向 APISIX 发起请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
## 删除插件
当你需要删除该插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,194 @@
---
title: tcp-logger
keywords:
- Apache APISIX
- API 网关
- Plugin
- TCP Logger
description: 本文介绍了 API 网关 Apache APISIX 如何使用 tcp-logger 插件将日志数据发送到 TCP 服务器。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`tcp-logger` 插件可用于将日志数据发送到 TCP 服务器。
该插件还实现了将日志数据以 JSON 格式发送到监控工具或其它 TCP 服务的能力。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------ | ------- | ------------------------------------------------ |
| host | string | 是 | | | TCP 服务器的 IP 地址或主机名。 |
| port | integer | 是 | | [0,...] | 目标端口。 |
| timeout | integer | 否 | 1000 | [1,...] | 发送数据超时间。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| tls | boolean | 否 | false | | 用于控制是否执行 SSL 验证。 |
| tls_options | string | 否 | | | TLS 选项。 |
| include_req_body | boolean | 否 | | [false, true] | 当设置为 `true` 时,日志中将包含请求体。 |
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | [false, true]| 当设置为 `true` 时,日志中将包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"response": {
"status": 200,
"headers": {
"server": "APISIX/3.7.0",
"content-type": "text/plain",
"content-length": "12",
"connection": "close"
},
"size": 118
},
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"start_time": 1704527628474,
"client_ip": "127.0.0.1",
"service_id": "",
"latency": 102.9999256134,
"apisix_latency": 100.9999256134,
"upstream_latency": 2,
"request": {
"headers": {
"connection": "close",
"host": "localhost"
},
"size": 59,
"method": "GET",
"uri": "/hello",
"url": "http://localhost:1984/hello",
"querystring": {}
},
"upstream": "127.0.0.1:1980",
"route_id": "1"
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `tcp-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/tcp-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```json
{"@timestamp":"2023-01-09T14:47:25+08:00","route_id":"1","host":"localhost","client_ip":"127.0.0.1"}
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"tcp-logger": {
"host": "127.0.0.1",
"port": 5044,
"tls": false,
"batch_max_size": 1,
"name": "tcp logger"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
现在你可以向 APISIX 发起请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
## 删除插件
当你需要删除该插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,202 @@
---
title: tencent-cloud-cls
keywords:
- Apache APISIX
- API 网关
- Plugin
- CLS
- 腾讯云
description: API 网关 Apache APISIX tencent-cloud-cls 插件可用于将日志推送到[腾讯云日志服务](https://cloud.tencent.com/document/product/614)。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`tencent-cloud-cls` 插件可用于将 APISIX 日志使用[腾讯云日志服务](https://cloud.tencent.com/document/product/614) API 推送到您的日志主题。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------- | ------ |-------| ------------ |------------------------------------------------------------------------------|
| cls_host | string | 是 | | | CLS API 域名,参考[使用 API 上传日志](https://cloud.tencent.com/document/api/614/16873)。|
| cls_topic | string | 是 | | | CLS 日志主题 id。 |
| secret_id | string | 是 | | | 云 API 密钥的 id。 |
| secret_key | string | 是 | | | 云 API 密钥的 key。 |
| sample_ratio | number | 否 | 1 | [0.00001, 1] | 采样的比例。设置为 `1` 时,将对所有请求进行采样。 |
| include_req_body | boolean | 否 | false | [false, true]| 当设置为 `true` 时,日志中将包含请求体。 |
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | [false, true]| 当设置为 `true` 时,日志中将包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
| global_tag | object | 否 | | | kv 形式的 JSON 数据,可以写入每一条日志,便于在 CLS 中检索。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
注意schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)
该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式示例
```json
{
"response": {
"headers": {
"content-type": "text/plain",
"connection": "close",
"server": "APISIX/3.7.0",
"transfer-encoding": "chunked"
},
"size": 136,
"status": 200
},
"route_id": "1",
"upstream": "127.0.0.1:1982",
"client_ip": "127.0.0.1",
"apisix_latency": 100.99985313416,
"service_id": "",
"latency": 103.99985313416,
"start_time": 1704525145772,
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"upstream_latency": 3,
"request": {
"headers": {
"connection": "close",
"host": "localhost"
},
"url": "http://localhost:1984/opentracing",
"querystring": {},
"method": "GET",
"size": 65,
"uri": "/opentracing"
}
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../../../en/latest/apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 重要
该设置全局生效。如果指定了 `log_format`,则所有绑定 `tencent-cloud-cls` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/tencent-cloud-cls \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```shell
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
{"host":"localhost","@timestamp":"2020-09-23T19:05:05-04:00","client_ip":"127.0.0.1","route_id":"1"}
```
## 启用插件
你可以通过以下命令在指定路由中启用该插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"tencent-cloud-cls": {
"cls_host": "ap-guangzhou.cls.tencentyun.com",
"cls_topic": "${your CLS topic name}",
"global_tag": {
"module": "cls-logger",
"server_name": "YourApiGateWay"
},
"include_req_body": true,
"include_resp_body": true,
"secret_id": "${your secret id}",
"secret_key": "${your secret key}"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
现在你可以向 APISIX 发起请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
## 删除插件
当你需要删除该插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,637 @@
---
title: traffic-split
keywords:
- APISIX
- API 网关
- Traffic Split
- 灰度发布
- 蓝绿发布
description: traffic-split 插件根据条件和/或权重将流量引导至各种上游服务。它提供了一种动态灵活的方法来实施发布策略和管理流量。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/traffic-split" />
</head>
## 描述
`traffic-split` 插件根据条件和/或权重将流量引导至各种上游服务。它提供了一种动态且灵活的方法来实施发布策略和管理流量。
:::note 注意
由于该插件使用了加权循环算法(特别是在重置 `wrr` 状态时),因此在使用该插件时,可能会存在上游服务之间的流量比例不精准现象。
:::
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------------- | --------------| ------ | ------ | ------ |-------------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------------------------------|
| rules.match | array[object] | 否 | | | 要执行的一对或多对匹配条件和操作的数组。 |
| rules.match | array[object] | 否 | | | 条件流量分割的匹配规则。 |
| rules.match.vars | array[array] | 否 | | | 以 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 形式包含一个或多个匹配条件的数组,用于有条件地执行插件。 |
| rules.weighted_upstreams | array[object] | 否 | | | 上游配置列表。 |
| rules.weighted_upstreams.upstream_id | 字符串/整数 | 否 | | | 配置的上游对象的 ID。 |
| rules.weighted_upstreams.weight | 整数 | 否 | weight = 1 | | 每个上游的权重。 |
| rules.weighted_upstreams.upstream | object | 否 | | | 上游配置。此处不支持某些上游配置选项。这些字段为 `service_name``discovery_type``checks``retries``retry_timeout``desc``labels`。作为解决方法,您可以创建一个上游对象并在 `upstream_id` 中配置它。|
| rules.weighted_upstreams.upstream.type | array | 否 | roundrobin | [roundrobin, chash] | 流量分割算法。`roundrobin` 用于加权循环,`chash` 用于一致性哈希。|
| rules.weighted_upstreams.upstream.hash_on | array | 否 | vars | | 当 `type``chash` 时使用。支持对 [NGINX 变量](https://nginx.org/en/docs/varindex.html)、headers、cookie、Consumer 或 [Nginx 变量](https://nginx.org/en/docs/varindex.html) 的组合进行哈希处理。 |
| rules.weighted_upstreams.upstream.key | string | 否 | | | 当 `type``chash` 时使用。当 `hash_on` 设置为 `header``cookie` 时,需要 `key`。当 `hash_on` 设置为 `consumer` 时,不需要 `key`,因为消费者名称将自动用作密钥。 |
| rules.weighted_upstreams.upstream.nodes | object | 否 | | | 上游节点的地址。 |
| rules.weighted_upstreams.upstream.timeout | object | 否 | 15 | | 连接、发送和接收消息的超时时间(秒)。 |
| rules.weighted_upstreams.upstream.pass_host | array | 否 | "pass" | ["pass", "node", "rewrite"] | 决定如何传递主机名的模式。`pass` 将客户端的主机名传递给上游。`node` 传递上游节点中配置的主机。`rewrite` 传递 `upstream_host` 中配置的值。|
| rules.weighted_upstreams.upstream.name | string | 否 | | | 用于指定服务名称、使用场景等的上游标识符。|
| rules.weighted_upstreams.upstream.upstream_host | string | 否 | | | 当 `pass_host``rewrite` 时使用。上游的主机名。|
## 示例
以下示例展示了使用 `traffic-split` 插件的不同用例。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 实现 Canary 发布
以下示例演示了如何使用此插件实现 Canary 发布。
Canary 发布是一种逐步部署,其中越来越多的流量被定向到新版本,从而实现受控和受监控的发布。此方法可确保在完全重定向所有流量之前,尽早识别和解决新版本中的任何潜在问题或错误。
创建路由并使用以下规则配置 `traffic-split` 插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 3
},
{
"weight": 2
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
```
每个 Upstream 的流量比例由该 Upstream 的权重占所有 Upstream 总权重的比例决定这里总权重计算为3 + 2 = 5。
因此60% 的流量要转发到 `httpbin.org`,另外 40% 的流量要转发到 `mock.api7.ai`
向路由发送 10 个连续请求来验证:
```shell
resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
```
您应该会看到类似以下内容的响应:
```text
httpbin.org: 6, mock.api7.ai: 4
```
相应地调整上游权重以完成金丝雀发布。
### 实现蓝绿部署
以下示例演示如何使用此插件实现蓝绿部署。
蓝绿部署是一种部署策略,涉及维护两个相同的环境:蓝色和绿色。蓝色环境指的是当前的生产部署,绿色环境指的是新的部署。一旦绿色环境经过测试可以投入生产,流量将被路由到绿色环境,使其成为新的生产部署。
创建路由并配置 `traffic-split` 插件,以便仅当请求包含标头 `release: new_release` 时才执行插件以重定向流量:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["http_release","==","new_release"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
}
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
```
向路由发送一个带有 `release` 标头的请求:
```shell
curl "http://127.0.0.1:9080/headers" -H 'release: new_release'
```
您应该会看到类似以下内容的响应:
```json
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
...
}
}
```
向路由发送一个不带任何附加标头的请求:
```shell
curl "http://127.0.0.1:9080/headers"
```
您应该会看到类似以下内容的响应:
```json
{
"headers": {
"accept": "*/*",
"host": "mock.api7.ai",
...
}
}
```
### 使用 APISIX 表达式定义 POST 请求的匹配条件
以下示例演示了如何在规则中使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list),在满足 POST 请求的某些条件时有条件地执行插件。
创建路由并使用以下规则配置 `traffic-split` 插件:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/post",
"methods": ["POST"],
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["post_arg_id", "==", "1"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
}
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
```
发送主体为 `id=1` 的 POST 请求:
```shell
curl "http://127.0.0.1:9080/post" -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'id=1'
```
您应该会看到类似以下内容的响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {
"id": "1"
},
"headers": {
"Accept": "*/*",
"Content-Length": "4",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
...
},
...
}
```
发送主体中不包含 `id=1` 的 POST 请求:
```shell
curl "http://127.0.0.1:9080/post" -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'random=string'
```
您应该看到请求已转发到 `mock.api7.ai`
### 使用 APISIX 表达式定义 AND 匹配条件
以下示例演示了如何在规则中使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list),在满足多个条件时有条件地执行插件。
创建路由并配置 `traffic-split` 插件,以便仅在满足所有三个条件时重定向流量:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["arg_name","==","jack"],
["http_user-id",">","23"],
["http_apisix-key","~~","[a-z]+"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 3
},
{
"weight": 2
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
```
如果满足条件,则 60% 的流量应定向到 `httpbin.org`,另外 40% 的流量应定向到 `mock.api7.ai`。如果不满足条件,则所有流量都应定向到 `mock.api7.ai`
发送 10 个满足所有条件的连续请求以验证:
```shell
resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=jack" -H 'user-id: 30' -H 'apisix-key: helloapisix' -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
```
您应该会看到类似以下内容的响应:
```text
httpbin.org: 6, mock.api7.ai: 4
```
连续发送 10 个不满足条件的请求进行验证:
```shell
resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=random" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
```
您应该会看到类似以下内容的响应:
```text
httpbin.org: 0, mock.api7.ai: 10
```
### 使用 APISIX 表达式定义或匹配条件
以下示例演示了如何在规则中使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list),在满足任一条件集时有条件地执行插件。
创建路由并配置 `traffic-split` 插件,以在满足任一配置条件集时重定向流量:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["arg_name","==","jack"],
["http_user-id",">","23"],
["http_apisix-key","~~","[a-z]+"]
]
},
{
"vars": [
["arg_name2","==","rose"],
["http_user-id2","!",">","33"],
["http_apisix-key2","~~","[a-z]+"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 3
},
{
"weight": 2
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
```
或者,您也可以使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 中的 OR 运算符来实现这些条件。
如果满足条件,则 60% 的流量应定向到 `httpbin.org`,其余 40% 应定向到 `mock.api7.ai`。如果不满足条件,则所有流量都应定向到 `mock.api7.ai`
发送 10 个满足第二组条件的连续请求以验证:
```shell
resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name2=rose" -H 'user-id:30' -H 'apisix-key2: helloapisix' -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
```
您应该会看到类似以下内容的响应:
```json
httpbin.org: 6, mock.api7.ai: 4
```
发送 10 个连续的不满足任何一组条件的请求来验证:
```shell
resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=random" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
```
您应该会看到类似以下内容的响应:
```json
httpbin.org: 0, mock.api7.ai: 10
```
### 为不同的上游配置不同的规则
以下示例演示了如何在规则集和上游之间设置一对一映射。
创建一个路由并使用以下匹配规则配置 `traffic-split` 插件,以便在请求包含标头 `x-api-id: 1``x-api-id: 2` 时将流量重定向到相应的上游服务:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "traffic-split-route",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["http_x-api-id","==","1"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 1
}
]
},
{
"match": [
{
"vars": [
["http_x-api-id","==","2"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
},
"weight": 1
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"postman-echo.com:443": 1
},
"scheme": "https",
"pass_host": "node"
}
}'
```
发送带有标头 `x-api-id: 1` 的请求:
```shell
curl "http://127.0.0.1:9080/headers" -H 'x-api-id: 1'
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
...
}
}
```
发送带有标头 `x-api-id: 2` 的请求:
```shell
curl "http://127.0.0.1:9080/headers" -H 'x-api-id: 2'
```
您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应:
```json
{
"headers": {
"accept": "*/*",
"host": "mock.api7.ai",
...
}
}
```
发送不带任何附加标头的请求:
```shell
curl "http://127.0.0.1:9080/headers"
```
您应该会看到类似以下内容的响应:
```json
{
"headers": {
"accept": "*/*",
"host": "postman-echo.com",
...
}
}
```

View File

@@ -0,0 +1,159 @@
---
title: ua-restriction
keywords:
- Apache APISIX
- API 网关
- UA restriction
description: ua-restriction 插件使用用户代理的允许列表或拒绝列表来限制对上游资源的访问,防止网络爬虫过载并增强 API 安全性。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/ua-restriction" />
</head>
## 描述
`ua-restriction` 插件支持通过配置用户代理的允许列表或拒绝列表来限制对上游资源的访问。一个常见的用例是防止网络爬虫使上游资源过载并导致服务降级。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| --------- | ------------- | ------ | ------ | ------ | -------------------------------- |
| bypass_missing |boolean| 否 | false | | 如果为 true则在缺少 `User-Agent` 标头时绕过用户代理限制检查。|
| allowlist | array[string] | 否 | | | 要允许的用户代理列表。支持正则表达式。应配置 `allowlist``denylist` 中至少一个,但不能同时配置。|
| denylist | array[string] | 否 | | | 要拒绝的用户代理列表。支持正则表达式。应配置 `allowlist``denylist` 中至少一个,但不能同时配置。|
| message | string | 否 | "Not allowed" | | 拒绝用户代理访问时返回的消息。|
## 示例
以下示例演示了如何针对不同场景配置 `ua-restriction`
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 拒绝网络爬虫并自定义错误消息
以下示例演示了如何配置插件以抵御不需要的网络爬虫并自定义拒绝消息。
创建路由并配置插件以使用自定义消息阻止特定爬虫访问资源:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "ua-restriction-route",
"uri": "/anything",
"plugins": {
"ua-restriction": {
"bypass_missing": false,
"denylist": [
"(Baiduspider)/(\\d+)\\.(\\d+)",
"bad-bot-1"
],
"message": "Access denied"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送请求:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到 `HTTP/1.1 200 OK` 响应。
使用不允许的用户代理向路由发送另一个请求:
```shell
curl -i "http://127.0.0.1:9080/anything" -H 'User-Agent: Baiduspider/5.0'
```
您应该收到 `HTTP/1.1 403 Forbidden` 响应,其中包含以下消息:
```text
{"message":"Access denied"}
```
### 绕过 UA 限制检查
以下示例说明如何配置插件以允许特定用户代理的请求绕过 UA 限制。
创建如下路由:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "ua-restriction-route",
"uri": "/anything",
"plugins": {
"ua-restriction": {
"bypass_missing": true,
"allowlist": [
"good-bot-1"
],
"message": "Access denied"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
```
向路由发送一个请求而不修改用户代理:
```shell
curl -i "http://127.0.0.1:9080/anything"
```
您应该收到一个 `HTTP/1.1 403 Forbidden` 响应,其中包含以下消息:
```text
{"message":"Access denied"}
```
向路由发送另一个请求,用户代理为空:
```shell
curl -i "http://127.0.0.1:9080/anything" -H 'User-Agent: '
```
您应该收到一个 `HTTP/1.1 200 OK` 响应。

View File

@@ -0,0 +1,191 @@
---
title: udp-logger
keywords:
- APISIX
- API 网关
- Plugin
- UDP Logger
description: 本文介绍了 API 网关 Apache APISIX 如何使用 udp-logger 插件将日志数据发送到 UDP 服务器。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`udp-logger` 插件可用于将日志数据发送到 UDP 服务器。
该插件还实现了将日志数据以 JSON 格式发送到监控工具或其它 UDP 服务的能力。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------ | ------- | ------------------------------------------------ |
| host | string | 是 | | | UDP 服务的 IP 地址或主机名。 |
| port | integer | 是 | | [0,...] | 目标端口。 |
| timeout | integer | 否 | 1000 | [1,...] | 发送数据超时间。 |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头,则表明是要获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
| name | string | 否 | "udp logger" | | 标识 logger 的唯一标识符。如果您使用 Prometheus 监视 APISIX 指标,名称将以 `apisix_batch_process_entries` 导出。 |
| include_req_body | boolean | 否 | | [false, true] | 当设置为 `true` 时,日志中将包含请求体。 |
| include_req_body_expr | array | 否 | | | 当 `include_req_body` 属性设置为 `true` 时的过滤器。只有当此处设置的表达式求值为 `true` 时,才会记录请求体。有关更多信息,请参阅 [lua-resty-expr](https://github.com/api7/lua-resty-expr) 。 |
| include_resp_body | boolean | 否 | false | [false, true]| 当设置为 `true` 时,日志中将包含响应体。 |
| include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 |
该插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)
### 默认日志格式数据
```json
{
"apisix_latency": 99.999988555908,
"service_id": "",
"server": {
"version": "3.7.0",
"hostname": "localhost"
},
"request": {
"method": "GET",
"headers": {
"connection": "close",
"host": "localhost"
},
"url": "http://localhost:1984/opentracing",
"size": 65,
"querystring": {},
"uri": "/opentracing"
},
"start_time": 1704527399740,
"client_ip": "127.0.0.1",
"response": {
"status": 200,
"size": 136,
"headers": {
"server": "APISIX/3.7.0",
"content-type": "text/plain",
"transfer-encoding": "chunked",
"connection": "close"
}
},
"upstream": "127.0.0.1:1982",
"route_id": "1",
"upstream_latency": 12,
"latency": 111.99998855591
}
```
## 插件元数据
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ---------------- | ------- | ------ | ------------- | ------- | ------------------------------------------------ |
| log_format | object | 否 | | | 以 JSON 格式的键值对来声明日志格式。对于值部分,仅支持字符串。如果是以 `$` 开头。则表明获取 [APISIX 变量](../apisix-variable.md)[NGINX 内置变量](http://nginx.org/en/docs/varindex.html)。 |
:::info 注意
该设置全局生效。如果指定了 `log_format`,则所有绑定 `udp-logger` 的路由或服务都将使用该日志格式。
:::
以下示例展示了如何通过 Admin API 配置插件元数据:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/udp-logger \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr"
}
}'
```
配置完成后,你将在日志系统中看到如下类似日志:
```json
{"@timestamp":"2023-01-09T14:47:25+08:00","route_id":"1","host":"localhost","client_ip":"127.0.0.1"}
```
## 如何开启
你可以通过如下命令在指定路由上启用 `udp-logger` 插件:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/5 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"plugins": {
"udp-logger": {
"host": "127.0.0.1",
"port": 3000,
"batch_max_size": 1,
"name": "udp logger"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'
```
## 测试插件
现在你可以向 APISIX 发起请求:
```shell
curl -i http://127.0.0.1:9080/hello
```
```
HTTP/1.1 200 OK
...
hello, world
```
## 删除插件
当你需要删除该插件时,可通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,117 @@
---
title: uri-blocker
keywords:
- Apache APISIX
- API 网关
- URI Blocker
description: 本文介绍了 Apache APISIX uri-blocker 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`uri-blocker` 插件通过指定一系列 `block_rules` 来拦截用户请求。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------- | ------------- | ------ | ------ | ---------- | ------------------------------------------------------------------- |
| block_rules | array[string] | 是 | | | 正则过滤数组。它们都是正则规则,如果当前请求 URI 命中其中任何一个,则将响应代码设置为 `rejected_code` 以退出当前用户请求。例如:`["root.exe", "root.m+"]`。 |
| rejected_code | integer | 否 | 403 | [200, ...] | 当请求 URI 命中 `block_rules` 中的任何一个时,将返回的 HTTP 状态代码。 |
| rejected_msg | string | 否 | | 非空 | 当请求 URI 命中 `block_rules` 中的任何一个时,将返回的 HTTP 响应体。 |
| case_insensitive | boolean | 否 | false | | 是否忽略大小写。当设置为 `true` 时,在匹配请求 URI 时将忽略大小写。 |
## 启用插件
以下示例展示了如何在指定的路由上启用 `uri-blocker` 插件:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/*",
"plugins": {
"uri-blocker": {
"block_rules": ["root.exe", "root.m+"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## 测试插件
启用并配置插件后,使用 `curl` 命令尝试访问 `block_rules` 中指定文件的 URI
```shell
curl -i http://127.0.0.1:9080/root.exe?a=a
```
如果发现返回了带有 `403` 状态码的 HTTP 响应头,则代表插件生效:
```shell
HTTP/1.1 403 Forbidden
Date: Wed, 17 Jun 2020 13:55:41 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 150
Connection: keep-alive
Server: APISIX web server
...
```
通过设置属性 `rejected_msg` 的值为 `access is not allowed`,将会收到包含如下信息的响应体:
```shell
...
{"error_msg":"access is not allowed"}
...
```
## 删除插件
当你需要禁用 `uri-blocker` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

View File

@@ -0,0 +1,301 @@
---
title: wolf-rbac
keywords:
- Apache APISIX
- API 网关
- Plugin
- wolf RBAC
- wolf-rbac
description: 本文介绍了关于 Apache APISIX `wolf-rbac` 插件的基本信息及使用方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
## 描述
`wolf-rbac` 插件为 [role-based access control](https://en.wikipedia.org/wiki/Role-based_access_control) 系统提供了添加 [wolf](https://github.com/iGeeky/wolf) 到 Route 或 Service 的功能。此插件需要与 [Consumer](../terminology/consumer.md) 一起使用。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 描述 |
| ------------- | ------ | ------ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| server | string | 否 | "http://127.0.0.1:12180" | `wolf-server` 的服务地址。 |
| appid | string | 否 | "unset" | 在 `wolf-console` 中已经添加的应用 id。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 |
| header_prefix | string | 否 | "X-" | 自定义 HTTP 头的前缀。`wolf-rbac` 在鉴权成功后,会在请求头 (用于传给后端) 及响应头 (用于传给前端) 中添加 3 个 header`X-UserId`, `X-Username`, `X-Nickname`。|
## 接口
该插件在启用时将会增加以下接口:
* /apisix/plugin/wolf-rbac/login
* /apisix/plugin/wolf-rbac/change_pwd
* /apisix/plugin/wolf-rbac/user_info
:::note
以上接口需要通过 [public-api](../../../en/latest/plugins/public-api.md) 插件暴露。
:::
## 前提条件
如果要使用这个插件,你必须要[安装 wolf](https://github.com/iGeeky/wolf/blob/master/quick-start-with-docker/README.md) 并启动它。
完成后,你需要添加`application``admin``regular user``permission``resource` 等字段,并将用户授权到 [wolf-console](https://github.com/iGeeky/wolf/blob/master/docs/usage.md)
## 启用插件
首先需要创建一个 Consumer 并配置该插件,如下所示:
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
```shell
curl http://127.0.0.1:9180/apisix/admin/consumers \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"username":"wolf_rbac",
"plugins":{
"wolf-rbac":{
"server":"http://127.0.0.1:12180",
"appid":"restful"
}
},
"desc":"wolf-rbac"
}'
```
:::note
示例中填写的 `appid`,必须是已经在 wolf 控制台中存在的。
:::
然后你需要添加 `wolf-rbac` 插件到 Route 或 Service 中。
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/*",
"plugins": {
"wolf-rbac": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"www.baidu.com:80": 1
}
}
}'
```
你还可以通过 [APISIX Dashboard](https://github.com/apache/apisix-dashboard) 的 Web 界面完成上述操作。
<!--
![add a consumer](https://raw.githubusercontent.com/apache/apisix/master/docs/assets/images/plugin/wolf-rbac-1.png)
![enable wolf-rbac plugin](https://raw.githubusercontent.com/apache/apisix/master/docs/assets/images/plugin/wolf-rbac-2.png)
-->
## 测试插件
你可以使用 [public-api](../../../en/latest/plugins/public-api.md) 插件来暴露 API.
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/wal \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"uri": "/apisix/plugin/wolf-rbac/login",
"plugins": {
"public-api": {}
}
}'
```
同样,你需要参考上述命令为 `change_pwd``user_info` 两个 API 配置路由。
现在你可以登录并获取 wolf `rbac_token`
```shell
curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \
-H "Content-Type: application/json" \
-d '{"appid": "restful", "username":"test", "password":"user-password", "authType":1}'
```
```
HTTP/1.1 200 OK
Date: Wed, 24 Jul 2019 10:33:31 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server
{"rbac_token":"V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts","user_info":{"nickname":"test","username":"test","id":"749"}}
```
:::note
上述示例中,`appid``username``password` 必须为 wolf 系统中真实存在的。
`authType` 为认证类型,`1` 为密码认证(默认),`2` 为 LDAP 认证。`wolf` 从 0.5.0 版本开始支持了 LDAP 认证。
:::
也可以使用 x-www-form-urlencoded 方式登陆:
```shell
curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'appid=restful&username=test&password=user-password'
```
现在开始测试 Route
- 缺少 token
```shell
curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" -i
```
```shell
HTTP/1.1 401 Unauthorized
...
{"message":"Missing rbac token in request"}
```
- token 放到请求头 (Authorization) 中:
```shell
curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \
-H 'Authorization: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i
```
```shell
HTTP/1.1 200 OK
<!DOCTYPE html>
```
- token 放到请求头 (x-rbac-token) 中:
```shell
curl http://127.0.0.1:9080/ -H"Host: www.baidu.com" \
-H 'x-rbac-token: V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -i
```
```shell
HTTP/1.1 200 OK
<!DOCTYPE html>
```
- token 放到请求参数中:
```shell
curl 'http://127.0.0.1:9080?rbac_token=V1%23restful%23eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts' -H"Host: www.baidu.com" -i
```
```shell
HTTP/1.1 200 OK
<!DOCTYPE html>
```
- token 放到 `cookie` 中:
```shell
curl http://127.0.0.1:9080 -H"Host: www.baidu.com" \
--cookie x-rbac-token=V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts -i
```
```shell
HTTP/1.1 200 OK
<!DOCTYPE html>
```
- 获取用户信息:
```shell
curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/user_info \
--cookie x-rbac-token=V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts -i
```
```shell
HTTP/1.1 200 OK
{
"user_info":{
"nickname":"test",
"lastLogin":1582816780,
"id":749,
"username":"test",
"appIDs":["restful"],
"manager":"none",
"permissions":{"USER_LIST":true},
"profile":null,
"roles":{},
"createTime":1578820506,
"email":""
}
}
```
- 更改用户的密码:
```shell
curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/change_pwd \
-H "Content-Type: application/json" \
--cookie x-rbac-token=V1#restful#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzQ5LCJ1c2VybmFtZSI6InRlc3QiLCJtYW5hZ2VyIjoiIiwiYXBwaWQiOiJyZXN0ZnVsIiwiaWF0IjoxNTc5NDQ5ODQxLCJleHAiOjE1ODAwNTQ2NDF9.n2-830zbhrEh6OAxn4K_yYtg5pqfmjpZAjoQXgtcuts -i \
-X PUT -d '{"oldPassword": "old password", "newPassword": "new password"}'
```
```shell
HTTP/1.1 200 OK
{"message":"success to change password"}
```
## 删除插件
当你需要禁用 `wolf-rbac` 插件时,可以通过以下命令删除相应的 JSON 配置APISIX 将会自动重新加载相关配置,无需重启服务:
```shell
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" -X PUT -d '
{
"methods": ["GET"],
"uri": "/*",
"plugins": {
},
"upstream": {
"type": "roundrobin",
"nodes": {
"www.baidu.com:80": 1
}
}
}'
```

View File

@@ -0,0 +1,386 @@
---
title: workflow
keywords:
- Apache APISIX
- API 网关
- Plugin
- workflow
- 流量控制
description: workflow 插件支持根据给定的一组规则有条件地执行对客户端流量的用户定义操作。这提供了一种实现复杂流量管理的细粒度方法。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/workflow" />
</head>
## 描述
`workflow` 插件支持根据给定的规则集有条件地执行对客户端流量的用户定义操作,这些规则集使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 定义。这为流量管理提供了一种细粒度的方法。
## 属性
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ------------- | ------ | ------ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| rules | array[object] | 是 | | | 一对或多对匹配条件和要执行的操作组成的数组。 |
| rules.case | array[array] | 否 | | | 一个或多个匹配条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list),例如 `{"arg_name", "==", "json"}`。 |
| rules.actions | array[object] | 是 | | | 条件匹配成功后要执行的操作的数组。目前数组只支持一个操作,必须是 `return` 或者 `limit-count`。当操作配置为 `return` 时,可以配置条件匹配成功时返回给客户端的 HTTP 状态码。当操作配置为 `limit-count` 时,可以配置 [`limit-count`](./limit-count.md) 插件除 `group` 之外的所有选项。 |
## 示例
以下示例演示了如何在不同场景中使用 `workflow` 插件。
:::note
您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```
:::
### 有条件地返回响应 HTTP 状态代码
以下示例演示了一个简单的规则,其中包含一个匹配条件和一个关联操作,用于有条件地返回 HTTP 状态代码。
使用 `workflow` 插件创建一个路由,当请求的 URI 路径为 `/anything/rejected` 时返回 HTTP 状态代码 403
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "workflow-route",
"uri": "/anything/*",
"plugins": {
"workflow":{
"rules":[
{
"case":[
["uri", "==", "/anything/rejected"]
],
"actions":[
[
"return",
{"code": 403}
]
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
发送与任何规则都不匹配的请求:
```shell
curl -i "http://127.0.0.1:9080/anything/anything"
```
您应该收到 `HTTP/1.1 200 OK` 响应。
发送与配置的规则匹配的请求:
```shell
curl -i "http://127.0.0.1:9080/anything/rejected"
```
您应该收到以下 `HTTP/1.1 403 Forbidden` 响应:
```text
{"error_msg":"rejected by workflow"}
```
### 通过 URI 和查询参数有条件地应用速率限制
以下示例演示了一条具有两个匹配条件和一个关联操作的规则,用于有条件地限制请求速率。
使用 `workflow` 插件创建路由,以在 URI 路径为 `/anything/rate-limit` 且查询参数 `env` 值为 `v1` 时应用速率限制:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "workflow-route",
"uri": "/anything/*",
"plugins":{
"workflow":{
"rules":[
{
"case":[
["uri", "==", "/anything/rate-limit"],
["arg_env", "==", "v1"]
],
"actions":[
[
"limit-count",
{
"count":1,
"time_window":60,
"rejected_code":429
}
]
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
生成两个符合第二条规则的连续请求:
```shell
curl -i "http://127.0.0.1:9080/anything/rate-limit?env=v1"
```
您应该收到 `HTTP/1.1 200 OK` 响应和 `HTTP 429 Too Many Requests` 响应。
生成不符合条件的请求:
```shell
curl -i "http://127.0.0.1:9080/anything/anything?env=v1"
```
您应该收到所有请求的 `HTTP/1.1 200 OK` 响应,因为它们不受速率限制。
### 消费者有条件地应用速率限制
以下示例演示了如何配置插件以根据以下规范执行速率限制:
* 消费者 `john` 在 30 秒内应有 5 个请求的配额
* 消费者 `jane` 在 30 秒内应有 3 个请求的配额
* 所有其他消费者在 30 秒内应有 2 个请求的配额
虽然此示例将使用 [`key-auth`](./key-auth.md),但您可以轻松地将其替换为其他身份验证插件。
创建消费者 `john`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "john"
}'
```
Create `key-auth` credential for the consumer:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
```
创建第二个消费者 `jane`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jane"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
```
创建第三个消费者 `jimmy`
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"username": "jimmy"
}'
```
为消费者创建 `key-auth` 凭证:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jimmy/credentials" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "cred-jimmy-key-auth",
"plugins": {
"key-auth": {
"key": "jimmy-key"
}
}
}'
```
使用 `workflow``key-auth` 插件创建路由,并设置所需的速率限制规则:
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "workflow-route",
"uri": "/anything",
"plugins":{
"key-auth": {},
"workflow":{
"rules":[
{
"actions": [
[
"limit-count",
{
"count": 5,
"key": "consumer_john",
"key_type": "constant",
"rejected_code": 429,
"time_window": 30
}
]
],
"case": [
[
"consumer_name",
"==",
"john"
]
]
},
{
"actions": [
[
"limit-count",
{
"count": 3,
"key": "consumer_jane",
"key_type": "constant",
"rejected_code": 429,
"time_window": 30
}
]
],
"case": [
[
"consumer_name",
"==",
"jane"
]
]
},
{
"actions": [
[
"limit-count",
{
"count": 2,
"key": "$consumer_name",
"key_type": "var",
"rejected_code": 429,
"time_window": 30
}
]
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
为了验证,请使用 `john` 的密钥发送 6 个连续的请求:
```shell
resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 6 个请求中5 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200 5429 1
```
使用 `jane` 的密钥连续发送 6 个请求:
```shell
resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jane-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 6 个请求中3 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200 3429 3
```
使用 `jimmy` 的密钥发送 3 个连续请求:
```shell
resp=$(seq 3 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jimmy-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
```
您应该看到以下响应,显示在 3 个请求中2 个请求成功(状态代码 200而其他请求被拒绝状态代码 429
```text
200 2429 1
```

View File

@@ -0,0 +1,265 @@
---
title: zipkin
keywords:
- Apache APISIX
- API 网关
- Plugin
- Zipkin
description: Zipkin 是一个开源的分布式链路追踪系统。`zipkin` 插件为 APISIX 提供了追踪功能,并根据 Zipkin API 规范将追踪数据上报给 Zipkin。
---
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
<head>
<link rel="canonical" href="https://docs.api7.ai/hub/zipkin" />
</head>
## 描述
[Zipkin](https://github.com/openzipkin/zipkin) 是一个开源的分布式链路追踪系统。`zipkin` 插件为 APISIX 提供了追踪功能,并根据 [Zipkin API 规范](https://zipkin.io/pages/instrumenting.html) 将追踪数据上报给 Zipkin。
该插件还支持将追踪数据发送到其他兼容的收集器,例如 [Jaeger](https://www.jaegertracing.io/docs/1.51/getting-started/#migrating-from-zipkin)[Apache SkyWalking](https://skywalking.apache.org/docs/main/latest/en/setup/backend/zipkin-trace/#zipkin-receiver),这两者都支持 Zipkin [v1](https://zipkin.io/zipkin-api/zipkin-api.yaml)[v2](https://zipkin.io/zipkin-api/zipkin2-api.yaml) API。
## 静态配置
默认情况下,`zipkin` 插件的 NGINX 变量配置在 [默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua) 中设置为 `false`
要修改此值,请将更新后的配置添加到 `config.yaml` 中。例如:
```yaml
plugin_attr:
zipkin:
set_ngx_var: true
```
重新加载 APISIX 以使更改生效。
## 属性
查看配置文件以获取所有插件可用的配置选项。
| 名称 | 类型 | 是否必需 | 默认值 | 有效值 | 描述 |
|--------------|---------|----------|----------------|-------------|------------------|
| endpoint | string | 是 | | | 要 POST 的 Zipkin span 端点,例如 `http://127.0.0.1:9411/api/v2/spans`。 |
|sample_ratio| number | 是 | | [0.00001, 1] | 请求采样频率。设置为 `1` 表示对每个请求进行采样。 |
|service_name| string | 否 | "APISIX" | | 在 Zipkin 中显示的服务名称。 |
|server_addr | string | 否 | `$server_addr` 的值 | IPv4 地址 | Zipkin 报告器的 IPv4 地址。例如,可以将其设置为你的外部 IP 地址。 |
|span_version| integer | 否 | `2` | [1, 2] | span 类型的版本。 |
## 示例
以下示例展示了使用 `zipkin` 插件的不同用例。
### 将追踪数据发送到 Zipkin
以下示例演示了如何追踪对路由的请求,并将追踪数据发送到使用 [Zipkin API v2](https://zipkin.io/zipkin-api/zipkin2-api.yaml) 的 Zipkin。还将介绍 span 版本 2 和 版本 1 之间的区别。
在 Docker 中启动一个 Zipkin 实例:
```shell
docker run -d --name zipkin -p 9411:9411 openzipkin/zipkin
```
创建一条路由,开启 `zipkin` 插件,并使用其默认的 `span_version`,即 `2`。同时请根据需要调整 Zipkin HTTP 端点的 IP 地址,将采样比率配置为 `1` 以追踪每个请求。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "zipkin-tracing-route",
"uri": "/anything",
"plugins": {
"zipkin": {
"endpoint": "http://127.0.0.1:9411/api/v2/spans",
"sample_ratio": 1,
"span_version": 2
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送请求:
```shell
curl "http://127.0.0.1:9080/anything"
```
你应该收到一个类似于以下的 `HTTP/1.1 200 OK` 响应:
```json
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/7.64.1",
"X-Amzn-Trace-Id": "Root=1-65af2926-497590027bcdb09e34752b78",
"X-B3-Parentspanid": "347dddedf73ec176",
"X-B3-Sampled": "1",
"X-B3-Spanid": "429afa01d0b0067c",
"X-B3-Traceid": "aea58f4b490766eccb08275acd52a13a",
"X-Forwarded-Host": "127.0.0.1"
},
...
}
```
导航到 Zipkin Web UI [http://127.0.0.1:9411/zipkin](http://127.0.0.1:9411/zipkin) 并点击 __Run Query__,你应该看到一个与请求对应的 trace
![来自请求的追踪](https://static.api7.ai/uploads/2024/01/23/MaXhacYO_zipkin-run-query.png)
点击 __Show__ 查看更多 trace 细节:
![v2 trace span](https://static.api7.ai/uploads/2024/01/23/3SmfFq9f_trace-details.png)
请注意,使用 span 版本 2 时,每个被 trace 的请求会创建以下 span
```text
request
├── proxy
└── response
```
其中 `proxy` 表示从请求开始到 `header_filter` 开始的时间,而 `response` 表示从 `header_filter` 开始到 `log` 开始的时间。
现在,更新路由上的插件以使用 span 版本 1
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes/zipkin-tracing-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"zipkin": {
"span_version": 1
}
}
}'
```
向路由发送另一个请求:
```shell
curl "http://127.0.0.1:9080/anything"
```
在 Zipkin Web UI 中,你应该看到一个具有以下细节的新 trace
![v1 trace span](https://static.api7.ai/uploads/2024/01/23/OPw2sTPa_v1-trace-spans.png)
请注意,使用较旧的 span 版本 1 时,每个被追踪的请求会创建以下 span
```text
request
├── rewrite
├── access
└── proxy
└── body_filter
```
### 将追踪数据发送到 Jaeger
以下示例演示了如何追踪对路由的请求并将追踪数据发送到 Jaeger。
在 Docker 中启动一个 Jaeger 实例:
```shell
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=9411 \
-p 16686:16686 \
-p 9411:9411 \
jaegertracing/all-in-one
```
创建一条路由并开启 `zipkin` 插件。请根据需要调整 Zipkin HTTP 端点的 IP 地址,并将采样比率配置为 `1` 以追踪每个请求。
```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "zipkin-tracing-route",
"uri": "/anything",
"plugins": {
"zipkin": {
"endpoint": "http://127.0.0.1:9411/api/v2/spans",
"sample_ratio": 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org": 1
}
}
}'
```
向路由发送请求:
```shell
curl "http://127.0.0.1:9080/anything"
```
你应该收到一个 `HTTP/1.1 200 OK` 响应。
导航到 Jaeger Web UI [http://127.0.0.1:16686](http://127.0.0.1:16686),选择 APISIX 作为服务,并点击 __Find Traces__,您应该看到一个与请求对应的 trace
![jaeger trace](https://static.api7.ai/uploads/2024/01/23/X6QdLN3l_jaeger.png)
同样地,一旦点击进入一个追踪,你应该会找到更多 span 细节:
![jaeger 细节](https://static.api7.ai/uploads/2024/01/23/iP9fXI2A_jaeger-details.png)
### 在日志中使用追踪变量
以下示例演示了如何配置 `zipkin` 插件以设置以下内置变量,这些变量可以在日志插件或访问日志中使用:
- `zipkin_context_traceparent`: [W3C trace context](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format)
- `zipkin_trace_id`: 当前 span 的 trace_id
- `zipkin_span_id`: 当前 span 的 span_id
按照以下方式更新配置文件。你可以自定义访问日志格式以使用 `zipkin` 插件变量,并在 `set_ngx_var` 字段中设置 `zipkin` 变量。
```yaml title="conf/config.yaml"
nginx_config:
http:
enable_access_log: true
access_log_format: '{"time": "$time_iso8601","zipkin_context_traceparent": "$zipkin_context_traceparent","zipkin_trace_id": "$zipkin_trace_id","zipkin_span_id": "$zipkin_span_id","remote_addr": "$remote_addr"}'
access_log_format_escape: json
plugin_attr:
zipkin:
set_ngx_var: true
```
重新加载 APISIX 以使配置更改生效。
当生成请求时,你应该看到类似的访问日志:
```text
{"time": "23/Jan/2024:06:28:00 +0000","zipkin_context_traceparent": "00-61bce33055c56f5b9bec75227befd142-13ff3c7370b29925-01","zipkin_trace_id": "61bce33055c56f5b9bec75227befd142","zipkin_span_id": "13ff3c7370b29925","remote_addr": "172.28.0.1"}
```