feat(proxy): entry-level URL rewriting via proxy.url_rewrites - #878
Closed
jarvis9443 wants to merge 3 commits into
Closed
feat(proxy): entry-level URL rewriting via proxy.url_rewrites#878jarvis9443 wants to merge 3 commits into
jarvis9443 wants to merge 3 commits into
Conversation
An ordered list of {match, rewrite} regex rules applied to every
proxy-listener request before route matching (admin/metrics listeners
unaffected): the first matching rule rewrites the path once — no
cascading — and the request then flows through the normal endpoint
(auth, ACL, quota, metrics labelling) as if the client had sent the
rewritten path. Replacement substitutes the matched portion with
$1/${name} capture-group expansion; the query string is preserved; a
miss leaves the request untouched. Invalid regexes fail startup.
Because axum's Router::layer middleware runs after route matching, the
rewrite gets its pre-routing seat by wrapping the whole router as the
fallback of an outer router; the wrapper is only built when rules are
configured, so the default path pays nothing.
Lets operators map legacy URL shapes onto AISIX endpoints without
client changes — e.g. per-server MCP paths like /mcp-servers/{svc}/mcp
onto the /mcp/{server} endpoint, completing the migration scenario of
api7/AISIX-Cloud#1219 together with the scoped-endpoint PR.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #875 (the
/mcp/{server}scoped endpoint); only the top commit is new here.What
Adds
proxy.url_rewrites: an ordered list of entry-level URL rewrite rules applied to every proxy-listener request before route matching (the admin and metrics listeners are unaffected).matchregex matches the request path rewrites it — once, no cascading — and the request then flows through the normal endpoint (auth, ACL, quota, metrics labelling) exactly as if the client had sent the rewritten path. A miss leaves the request untouched.rewritereplaces the matched portion of the path;$1/${name}expand capture groups; the query string is preserved as sent.Config::validate), so a typo surfaces at boot instead of as every legacy request 404ing. A template that assembles an invalid path at runtime logs a warning naming the rule and leaves the request unrewritten.Implementation note: axum's
Router::layermiddleware runs after route matching, so a URI rewritten there could never change which route matches. The rewrite therefore wraps the whole router as the fallback of an outer router, giving it a genuine pre-routing seat.Why
Lets operators map legacy URL shapes onto AISIX endpoints without client changes. The flagship scenario (api7/AISIX-Cloud#1219): clients migrating from gateways that expose one URL per MCP server (
/mcp-servers/{service}/{path}) keep their configured URLs and original tool names — one rule maps the URL onto the/mcp/{server}endpoint from #875, and the whole existing governance chain applies unchanged.Design comparison (per repo rule): mainstream gateways all ship a regex path-rewrite primitive with matched-portion replacement and capture-group templates (route-plugin, per-route rewrite, or middleware forms). Ours differs in placement only — a gateway-global ordered rule list instead of per-route config — because AISIX's routes are fixed built-in endpoints and the layer's purpose is mapping external URL space onto them; first-match-wins order replaces per-route attachment. LiteLLM offers no operator-configurable equivalent (its per-server MCP alias route is an internal fixed rewrite of the same shape), so the APISIX-style rewrite plugins are the reference baseline here.
Rewriting cannot bypass governance: it only re-targets which proxy endpoint serves the request, and every endpoint enforces its own auth/ACL/quota after the rewrite; the admin surface lives on a separate listener the layer never touches.
Tests
crates/aisix-proxy/src/rewrite.rs— unit + router-level: capture groups, matched-portion semantics, named/braced references, query preservation, invalid-path fallback, first-rule-wins through the real router, no-rules passthrough.crates/aisix-core/src/config.rs— config load + invalid-regex boot rejection.tests/e2e/src/cases/url-rewrite-e2e.test.ts— real binary + etcd + real MCP upstream: the full migration scenario (legacy per-server URL + original tool name end to end), generic non-MCP mapping, query survival, miss-passthrough (canonical paths intact, unmatched legacy tails 404).config.example.yaml/config.managed.yamldocument the block. Fixes api7/AISIX-Cloud#1219.