This is an automated email from the ASF dual-hosted git repository.
baoyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 18884bcad feat: add ksuid algorithm on request-id plugin (#12573)
18884bcad is described below
commit 18884bcad48771e5e05586db4c3932cdb6afc6e0
Author: YH <[email protected]>
AuthorDate: Fri Sep 5 15:20:48 2025 +0800
feat: add ksuid algorithm on request-id plugin (#12573)
---
apisix-master-0.rockspec | 1 +
apisix/plugins/request-id.lua | 7 +-
docs/en/latest/plugins/request-id.md | 55 ++++++++++++-
docs/zh/latest/plugins/request-id.md | 55 ++++++++++++-
t/plugin/request-id3.t | 154 +++++++++++++++++++++++++++++++++++
5 files changed, 269 insertions(+), 3 deletions(-)
diff --git a/apisix-master-0.rockspec b/apisix-master-0.rockspec
index abc5f3a76..83f6309ec 100644
--- a/apisix-master-0.rockspec
+++ b/apisix-master-0.rockspec
@@ -40,6 +40,7 @@ dependencies = {
"lua-resty-balancer = 0.04",
"lua-resty-ngxvar = 0.5.2",
"lua-resty-jit-uuid = 0.0.7",
+ "lua-resty-ksuid = 1.0.1",
"lua-resty-worker-events = 1.0.0",
"lua-resty-healthcheck-api7 = 3.2.0",
"api7-lua-resty-jwt = 0.2.5",
diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua
index dac3162db..d9569302a 100644
--- a/apisix/plugins/request-id.lua
+++ b/apisix/plugins/request-id.lua
@@ -19,6 +19,7 @@ local ngx = ngx
local core = require("apisix.core")
local uuid = require("resty.jit-uuid")
local nanoid = require("nanoid")
+local ksuid = require("resty.ksuid")
local math_random = math.random
local str_byte = string.byte
local ffi = require "ffi"
@@ -32,7 +33,7 @@ local schema = {
include_in_response = {type = "boolean", default = true},
algorithm = {
type = "string",
- enum = {"uuid", "nanoid", "range_id"},
+ enum = {"uuid", "nanoid", "range_id", "ksuid"},
default = "uuid"
},
range_id = {
@@ -87,6 +88,10 @@ local function get_request_id(conf)
return get_range_id(conf.range_id)
end
+ if conf.algorithm == "ksuid" then
+ return ksuid.generate()
+ end
+
return uuid()
end
diff --git a/docs/en/latest/plugins/request-id.md
b/docs/en/latest/plugins/request-id.md
index 3f5fb398b..3d998ac21 100644
--- a/docs/en/latest/plugins/request-id.md
+++ b/docs/en/latest/plugins/request-id.md
@@ -40,7 +40,7 @@ The `request-id` Plugin adds a unique ID to each request
proxied through APISIX,
| ------------------- | ------- | -------- | -------------- |
------------------------------- |
---------------------------------------------------------------------- |
| header_name | string | False | "X-Request-Id" |
| Name of the header that carries the request unique ID. Note
that if a request carries an ID in the `header_name` header, the Plugin will
use the header value as the unique ID and will not overwrite it with the
generated ID. |
| include_in_response | boolean | False | true |
| If true, include the generated request ID in the response
header, where the name of the header is the `header_name` value. |
-| algorithm | string | False | "uuid" |
["uuid","nanoid","range_id"] | Algorithm used for generating the unique ID.
When set to `uuid` , the Plugin generates a universally unique identifier. When
set to `nanoid`, the Plugin generates a compact, URL-safe ID. When set to
`range_id`, the Plugin generates a sequential ID with specific parameters.
|
+| algorithm | string | False | "uuid" |
["uuid","nanoid","range_id","ksuid"] | Algorithm used for generating the unique
ID. When set to `uuid` , the Plugin generates a universally unique identifier.
When set to `nanoid`, the Plugin generates a compact, URL-safe ID. When set to
`range_id`, the Plugin generates a sequential ID with specific parameters. When
set to `ksuid`, the Plugin generates a sequential ID with timestamp and random
number. |
| range_id | object | False | | | Configuration for generating a
request ID using the `range_id` algorithm. |
| range_id.char_set | string | False |
"abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789" | minimum
length 6 | Character set used for the `range_id` algorithm. |
| range_id.length | integer | False | 16 | >=6 | Length of the
generated ID for the `range_id` algorithm. |
@@ -243,6 +243,59 @@ You should receive an `HTTP/1.1 200 OK` response and see
the response includes t
X-Request-Id: kepgHWCH2ycQ6JknQKrX2
```
+### Use `ksuid` Algorithm
+
+The following example demonstrates how to configure `request-id` on a Route
and use the `ksuid` algorithm to generate the request ID.
+
+Create a Route with the `request-id` Plugin as such:
+
+```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": "ksuid"
+ }
+ },
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "httpbin.org:80": 1
+ }
+ }
+ }'
+```
+
+Send a request to the Route:
+
+```shell
+curl -i "http://127.0.0.1:9080/anything"
+```
+
+You should receive an `HTTP/1.1 200 OK` response and see the response includes
the `X-Request-Id` header with an ID generated using the `ksuid` algorithm:
+
+```text
+X-Request-Id: 325ghCANEKjw6Jsfejg5p6QrLYB
+```
+
+If the
[ksuid](https://github.com/segmentio/ksuid?tab=readme-ov-file#command-line-tool)
is installed, this ID can be viewed through `ksuid -f inspect
325ghCANEKjw6Jsfejg5p6QrLYB`:
+
+``` text
+REPRESENTATION:
+
+ String: 325ghCANEKjw6Jsfejg5p6QrLYB
+ Raw: 15430DBBD7F68AD7CA0AE277772AB36DDB1A3C13
+
+COMPONENTS:
+
+ Time: 2025-09-01 16:39:23 +0800 CST
+ Timestamp: 356715963
+ Payload: D7F68AD7CA0AE277772AB36DDB1A3C13
+```
+
### Attach Request ID Globally and on a Route
The following example demonstrates how to configure `request-id` as a global
Plugin and on a Route to attach two IDs.
diff --git a/docs/zh/latest/plugins/request-id.md
b/docs/zh/latest/plugins/request-id.md
index 7747fc70a..371319a77 100644
--- a/docs/zh/latest/plugins/request-id.md
+++ b/docs/zh/latest/plugins/request-id.md
@@ -36,7 +36,7 @@ description: request-id 插件为通过 APISIX 代理的每个请求添加一个
| ------------------- | ------- | -------- | -------------- | ------ |
------------------------------ |
| 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。|
+| algorithm | string | 否 | "uuid" | ["uuid","nanoid","range_id","ksuid"] |
用于生成唯一 ID 的算法。设置为 `uuid` 时,插件会生成一个通用唯一标识符。设置为 `nanoid` 时,插件会生成一个紧凑的、URL 安全的
ID。设置为 `range_id` 时,插件会生成具有特定参数的连续 ID。设置为 `ksuid` 时,插件会生成具有时间戳和随机值的连续 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 的长度。|
@@ -239,6 +239,59 @@ curl -i "http://127.0.0.1:9080/anything"
X-Request-Id: kepgHWCH2ycQ6JknQKrX2
```
+### 使用 `ksuid` 算法
+
+以下示例演示如何在路由上配置 `request-id` 并使用 `ksuid` 算法生成请求 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": "ksuid"
+ }
+ },
+ "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 使用 `ksuid` 算法生成:
+
+```text
+X-Request-Id: 325ghCANEKjw6Jsfejg5p6QrLYB
+```
+
+如果装有[ksuid](https://github.com/segmentio/ksuid?tab=readme-ov-file#command-line-tool)命令工具,此
ID 可以通过`ksuid -f inspect 325ghCANEKjw6Jsfejg5p6QrLYB`查看:
+
+``` text
+REPRESENTATION:
+
+ String: 325ghCANEKjw6Jsfejg5p6QrLYB
+ Raw: 15430DBBD7F68AD7CA0AE277772AB36DDB1A3C13
+
+COMPONENTS:
+
+ Time: 2025-09-01 16:39:23 +0800 CST
+ Timestamp: 356715963
+ Payload: D7F68AD7CA0AE277772AB36DDB1A3C13
+```
+
### 全局和在路由上附加请求 ID
以下示例演示如何将 `request-id` 配置为全局插件并在路由上附加两个 ID。
diff --git a/t/plugin/request-id3.t b/t/plugin/request-id3.t
new file mode 100644
index 000000000..a377d6e81
--- /dev/null
+++ b/t/plugin/request-id3.t
@@ -0,0 +1,154 @@
+#
+# 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.
+#
+use t::APISIX 'no_plan';
+
+worker_connections(1024);
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ if (!$block->request) {
+ $block->set_value("request", "GET /t");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: check config with algorithm ksuid
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "request-id": {
+ "algorithm": "ksuid"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1982": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 2: hit
+--- request
+GET /opentracing
+--- error_log
+X-Request-Id
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: add plugin with algorithm ksuid
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require "resty.http"
+ local v = {}
+ local ids = {}
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "request-id": {
+ "algorithm": "ksuid"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1982": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/opentracing"
+ }]]
+ )
+ if code >= 300 then
+ ngx.say("algorithm ksuid is error")
+ end
+ for i = 1, 180 do
+ local th = assert(ngx.thread.spawn(function()
+ local httpc = http.new()
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port ..
"/opentracing"
+ local res, err = httpc:request_uri(uri,
+ {
+ method = "GET",
+ headers = {
+ ["Content-Type"] = "application/json",
+ }
+ }
+ )
+ if not res then
+ ngx.log(ngx.ERR, err)
+ return
+ end
+ local id = res.headers["X-Request-Id"]
+ if not id then
+ return -- ignore if the data is not synced yet.
+ end
+ if #id ~= 27 then
+ ngx.say(id)
+ ngx.say("incorrect length for id")
+ return
+ end
+ local start, en = string.find(id, '[a-zA-Z0-9]*')
+ if start ~= 1 or en ~= 27 then
+ ngx.say("incorrect char set for id")
+ ngx.say(id)
+ return
+ end
+ if ids[id] == true then
+ ngx.say("ids not unique")
+ return
+ end
+ ids[id] = true
+ end, i))
+ table.insert(v, th)
+ end
+ for i, th in ipairs(v) do
+ ngx.thread.wait(th)
+ end
+ ngx.say("true")
+ }
+ }
+--- wait: 5
+--- response_body
+true