Router Options
In APISIX, there are three HTTP router options:
radixtree_host_uri
routes requests by hosts and URI paths, prioritizing hostnames over URI paths during matching. This is the default setting and the behaviour is the same as NGINX.radixtree_uri
routes requests by hosts and URI paths, prioritizing URI paths over hostnames during matching.radixtree_uri_with_parameter
supports the use of parameters in path matching.
These router options can be configured in conf/config.yaml
under apisix.router.http
.
radixtree_host_uri
This is the default router setting, which prioritizes hostnames over URI paths when route matching. If you would like to explicitly configure the option, add the following block to your configuration file:
apisix:
router:
http: radixtree_host_uri
Reload APISIX for changes to take effect.
Configuring two routes with the same URI but different matching hosts is useful for scenarios like multi-tenant SaaS platforms, where each tenant is served through a custom subdomain. For example, both tenants may access the same endpoint, but the requests are routed to different upstream services based on the host.
To do so, you can configure two routes with the same matching URI but different matching hosts and upstream services:
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "httpbin-host-test1",
"uri": "/get",
"host": "test1.com",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "postman-host-test2",
"uri": "/get",
"host": "test2.com",
"upstream": {
"type": "roundrobin",
"nodes": {
"postman-echo.com:80": 1
}
}
}'
Send a request that matches the host of the first route:
curl "http://127.0.0.1:9080/get" -H 'host: test1.com'
You should see a response from httpbin.org
:
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "test1.com",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-6746c0bf-653fac896be8818275f1e8da",
"X-Forwarded-Host": "test1.com"
},
"origin": "192.168.65.1, 43.252.208.90",
"url": "http://test1.com/get"
}
Send a request that matches the host of the second route:
curl "http://127.0.0.1:9080/get" -H 'host: test2.com'
You should see a response from postman-echo.com
:
{
"args": {},
"headers": {
"host": "test2.com",
"x-request-start": "t=1732834286",
"connection": "close",
"x-forwarded-proto": "http",
"x-forwarded-port": "80",
"x-amzn-trace-id": "Root=1-6746c0ca-2b0b323902e784f512051ef6",
"x-forwarded-host": "test2.com",
"user-agent": "curl/8.6.0",
"accept": "*/*"
},
"url": "http://test2.com/get"
}
To understand the behaviour more, create a third route that matches all requests:
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "mock-api7-all",
"uri": "/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"mock.api7.ai:443": 1
},
"scheme": "https",
"pass_host": "node"
}
}'
Send a request with a random host name:
curl "http://127.0.0.1:9080/get" -H 'host: random.com'
You should see the request is forwarded to the third route:
API7.ai, the creator of Apache APISIX, delivers a cloud-native API Gateway solution for the Enterprise, to help you maximize the value of APIs.
Send another request that matches the host of the first route:
curl "http://127.0.0.1:9080/get" -H 'host: test1.com'
You should see the request is forwarded to the httpbin.org
upstream. This demonstrates how the router prioritizes hostnames in routing when it is set to radixtree_host_uri
.
radixtree_uri
radixtree_uri
prioritizes URI paths over hostnames when route matching. To use radixtree_uri
as the HTTP router setting, add the following block to your configuration file:
apisix:
router:
http: radixtree_uri
Reload APISIX for changes to take effect.
To understand the behaviour, create a route that matches test1.com
host and all URI paths:
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "httpbin-host-test1",
"uri": "/*",
"host": "test1.com",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Create another route that matches requests to /get
:
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "mock-api7-all",
"uri": "/get",
"upstream": {
"type": "roundrobin",
"nodes": {
"mock.api7.ai:443": 1
},
"scheme": "https",
"pass_host": "node"
}
}'
Send a request to /get
with test1.com
host:
curl "http://127.0.0.1:9080/get" -H 'host: test1.com'
You should see the request is forwarded to mock.api7.ai:
API7.ai, the creator of Apache APISIX, delivers a cloud-native API Gateway solution for the Enterprise, to help you maximize the value of APIs.
This shows the hostname is not being prioritized when router operates in radixtree_uri
mode and full path matching takes the priority.
Send another request to /anything
with test1.com
host:
curl "http://127.0.0.1:9080/anything" -H 'host: test1.com'
You should see the request is forwarded to the httpbin.org
upstream.
radixtree_uri_with_parameter
radixtree_uri_with_parameter
supports the use of parameters when route matching. To use radixtree_uri_with_parameter
as the HTTP router setting, add the following block to your configuration file:
apisix:
router:
http: radixtree_uri_with_parameter
Reload APISIX for changes to take effect.
A common use case is to extract a part of the URI path and use it to compose the request sent to upstream services. This provides flexibility in dynamic routing and customization based on client requests. For example, a URI path like /user/123/profile
could be matched, and the user ID 123
extracted and forwarded as in a new header to the upstream service.
To do so, create a route as such:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "httpbin",
"uri": "/anything/user/:user_id/profile",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function(conf, ctx)
local core = require \"apisix.core\"
local user_id = ctx.curr_req_matched.user_id
if user_id then
core.request.set_header(ctx, \"user-id\", user_id)
end
end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ Match requests to /anything/user/:user_id/profile
where user_id
is a parameter.
❷ Customize the serverless function to extract the user_id
value from the requested path and attach the value to a new header User-Id
.
To verify, send a request to the route:
curl -i "http://127.0.0.1:9080/anything/user/123/profile"
You should see the following response:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"User-Id": "123",
"X-Amzn-Trace-Id": "Root=1-6746b92d-509ab0186bd075c462ab0ac8",
"X-Forwarded-Host": "127.0.0.1"
},
...
}
The route parameter can also accept URL-encoded string. For instance, if you send a request as such:
curl -i "http://127.0.0.1:9080/anything/user/123%20456/profile"
The user ID would be extracted as 123 456
.
Understand Route Matching
APISIX leverages the luaradixtree library for routing, an adaptive radix tree implemented in Lua for OpenResty. It utilizes the Foreign Function Interface (FFI) to integrate with rax, ensuring efficient and high-performance routing.
There are several ways of route matching.
Full Path
Suppose the route URI is:
/anything/foo
The route will only match request to /anything/foo
.
Wildcard
Suppose the route URI is:
/anything/*
The route will match any request to sub-paths of /anything
, such as /anything/foo
and /anything/bar
. Note that it will not match requests to /anything
.
The wildcard does not need to be at the end of the URI. You can also have a route URI as such:
/*/*/test
This will match requests with URIs like /anything/foo/test
.
Matching Priority
Full path matching has a higher priority than wildcard matching. Suppose you have two routes with URI /anything/foo
and /anything/*
respectively. The request to /anything/foo
will be matched by the /anything/foo
route, instead of the /anything/*
route.