Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Router Configuration

router.yml configures the HTTP router used by Java light-4j gateways/sidecars and the Rust light-fabric gateway. It controls downstream protocol selection, request deadlines, streaming responses, connection policies, forwarding headers, explicit-URL host restrictions, request rewrites, and downstream timing metrics.

In Java, com.networknt.router.RouterHandler is an HttpHandler wrapper around the final ProxyHandler. It can be installed through handler.yml, or through a RouterHandlerProvider in service.yml, as described by Portal’s config_t.config_desc. In Rust, the gateway’s router handler loads the shared light-pingora Router configuration and uses it when selecting and forwarding HTTP targets.

The two runtimes share the configuration vocabulary and intended routing contract. They do not currently enforce every property in the same way. The reference below distinguishes implemented behavior from compatibility-only fields and documents concrete differences. mcp-router.yml and websocket-router.yml are separate configurations; this page is not a complete specification of MCP or WebSocket routing.

Configure it in Portal, values.yml, or router.yml

In Portal, choose the router configuration and set the named property, for example maxRequestTime, to 5000. The property descriptions stored in config_property_t.property_desc explain the purpose; the effective value depends on the configuration assembled for the target instance. Check the generated/resolved configuration and the runtime’s loaded configuration after applying a change.

The source templates externalize values using the router. prefix:

# Fragment of a router.yml template
maxRequestTime: ${router.maxRequestTime:1000}
urlRewriteRules: ${router.urlRewriteRules:}

${router.maxRequestTime:1000} means use the externalized router.maxRequestTime value, or 1000 when absent. It is configuration-loader syntax, not an ordinary literal YAML integer. Rust’s shipped gateway template instead uses 0 for that timeout fallback.

In a values.yml file, set the externalized keys:

router.maxRequestTime: 5000
router.pathPrefixMaxRequestTime:
  /v1/address: 10000
router.urlRewriteRules:
  - '/v1/api/(.*) /api/$1'

This gives ordinary requests five seconds, address requests ten seconds, and rewrites /v1/api/orders to /api/orders. In a resolved router.yml, the same values use unprefixed keys:

maxRequestTime: 5000
pathPrefixMaxRequestTime:
  /v1/address: 10000
urlRewriteRules:
  - '/v1/api/(.*) /api/$1'

Do not wrap these entries in a top-level router: object. Native YAML lists/maps are easiest to read; source examples also use JSON lists/maps and JSON text stored in quoted YAML scalars. A JSON editor expects valid JSON with double-quoted strings and doubled regex backslashes. Single-quoted YAML strings preserve regex backslashes literally. Keep integer settings numeric and quote string rewrite values such as '1'.

An empty list ([]) disables configured list rules; an empty map ({}) removes map overrides. For hostWhitelist, an empty list specifically denies explicit-URL routing. Blank externalized placeholders in older Java templates denote no configured value; they are not examples of nonempty rule syntax.

All router.yml properties

The defaults below come from current source templates/models and the local Portal configuration catalog. A property value explicitly generated by Portal overrides a runtime fallback. Java and Rust timeouts are nonnegative millisecond values for portable configuration; 0 has the documented disabled meaning for deadline/idle settings.

PropertyTypeDefaultPurpose
http2EnabledBooleantrueEnable outbound HTTP/2 negotiation.
httpsEnabledBooleantrueControl TLS for Java discovery and HTTPS discovery filtering in Rust.
maxRequestTimeInteger (ms)Java: 1000; Rust: 0Ordinary request deadline; 0 disables this deadline.
pathPrefixMaxRequestTimeMap of integer (ms){}Override the ordinary deadline by literal request-path prefix.
streamResponseContentTypesList of string[text/event-stream]Recognize streaming responses by Content-Type.
streamRequestAcceptTypesList of string[text/event-stream]Recognize expected streams by Accept.
streamPathPrefixesList of string[]Declare streaming request paths before response headers arrive.
streamMaxRequestTimeInteger (ms)0Streaming exchange deadline; 0 disables it.
streamIdleTimeoutInteger (ms)0Maximum silence between downstream streaming bytes; 0 disables it.
streamResponseHeaderOverwriteList of stringSix headers; see property pageGive downstream streaming headers precedence over existing response headers.
connectionsPerThreadInteger10Java per-target, per-I/O-thread pool connection limit.
maxQueueSizeInteger0Java pending connection-request queue limit.
softMaxConnectionsPerThreadInteger5Java soft connection-pool limit.
rewriteHostHeaderBooleantrueSet Host for the selected target and retain the original in X-Forwarded-Host.
reuseXForwardedBooleanfalseReuse forwarding metadata from a trusted preceding proxy.
maxConnectionRetriesInteger3Java proxy connection retry limit.
preResolveFQDN2IPBooleanfalseJava discovery-time hostname-to-IP conversion.
hostWhitelistList of regex string[]Allow explicit service_url hosts; an empty list denies them.
serviceIdQueryParameterBooleanfalseAllow query service_id to override header service_id.
urlRewriteRulesList of string[]Rewrite the path with the first matching regex.
methodRewriteRulesList of string[]Rewrite the method for an endpoint pattern.
queryParamRewriteRulesMap of rule lists{}Rename existing query keys and conditionally replace values.
headerRewriteRulesMap of rule lists{}Rename existing headers and conditionally replace values.
metricsInjectionBooleanfalseRequest Java downstream-latency injection into the metrics handler.
metricsNameStringrouter-responseName for injected Java downstream timing metrics.

Every property link above has an explanation, examples, and runtime qualifications. The following examples show how the settings fit together.

How routing and rewriting fit together

  1. Earlier handlers authenticate/authorize the request and can derive service_id from a path, endpoint, or other mapping.
  2. If serviceIdQueryParameter is enabled, a query service_id can override the service-ID header.
  3. An explicit service_url takes precedence over service-ID discovery and must pass hostWhitelist. Otherwise the router resolves the registered service_id, with env_tag when supplied. Rust can use Portal registry discovery and direct-registry fallback.
  4. The router selects timeout/streaming policy using the incoming path and request metadata.
  5. The proxy adapts the upstream method, headers, path, and query. A target base path can be prepended. The routing headers service_id and service_url are removed before forwarding.
  6. The backend response is transferred; a configured streaming Content-Type triggers streaming handling, header precedence, and optional idle limits.

For example, service_id: party.address-1.0.0 selects a registered service, whereas service_url: https://api.example.com:8443/base selects an explicit target. With the latter target, an incoming /v1/address is forwarded under /base/v1/address, subject to any URL rewrite. A rewrite changes the backend-facing path; it does not itself select a different service or rerun authentication/authorization already performed by preceding handlers.

For service-to-URL mappings and Kubernetes ingress base paths, see Direct Registry Configuration. See Handler Configuration for where a router is placed in the request chain.

Choose the right matching language

PropertyMatching languageExample and meaning
pathPrefixMaxRequestTimeLiteral string prefix/v1/pets/ matches /v1/pets/123; {petId} is not expanded.
streamPathPrefixesLiteral string prefix/events/ classifies /events/orders before response headers.
urlRewriteRulesWhole-path regular expression/listings/(.*)$ captures a suffix for $1.
methodRewriteRulesEndpoint pattern/v1/pets/{petId} targets an identifier-bearing endpoint.
queryParamRewriteRules, headerRewriteRulesEndpoint-pattern map, with runtime differences/v1/pets/{petId} chooses a list of field rewrite rules.
hostWhitelistWhole-hostname regular expressionapi\.example\.com allows the named host, independently of its port/path.

Use nonoverlapping endpoint/prefix rules for portable behavior. Java’s endpoint matcher and Rust’s endpoint matcher have different prefix/selection behavior, described on the relevant property pages.

Complete resolved configuration example

This example includes all 25 properties. It chooses an explicit ordinary timeout to avoid default drift, declares an SSE path, leaves adaptation rules empty, and uses registered service routing by default.

http2Enabled: true
httpsEnabled: true
maxRequestTime: 1000
pathPrefixMaxRequestTime:
  /v1/address: 5000
  /v2/address: 10000
  /v3/address: 30000
streamResponseContentTypes:
  - text/event-stream
streamRequestAcceptTypes:
  - text/event-stream
streamPathPrefixes:
  - /events/
streamMaxRequestTime: 0
streamIdleTimeout: 30000
streamResponseHeaderOverwrite:
  - Content-Type
  - Cache-Control
  - Connection
  - Transfer-Encoding
  - Content-Encoding
  - Content-Length
connectionsPerThread: 10
maxQueueSize: 0
softMaxConnectionsPerThread: 5
rewriteHostHeader: true
reuseXForwarded: false
maxConnectionRetries: 3
preResolveFQDN2IP: false
hostWhitelist: []
serviceIdQueryParameter: false
urlRewriteRules: []
methodRewriteRules: []
queryParamRewriteRules: {}
headerRewriteRules: {}
metricsInjection: false
metricsName: router-response

The settings mean:

  • Protocols: HTTP/2 is enabled for backend negotiation. Java uses HTTPS discovery; Rust permits HTTPS discovery and uses target protocols. Configure the incoming listener and TLS material separately.
  • Ordinary requests: unmatched paths have one second; address API versions have five, ten, and thirty seconds. Prefixes are evaluated against the incoming path.
  • Streams: /events/orders is declared streaming from the start. SSE is also recognized by Accept/Content-Type. A stream has no configured total deadline, but thirty seconds without upstream bytes closes a confirmed stream. The six header names protect downstream stream metadata from existing ordinary-response headers.
  • Java pools: ten connections per backend per I/O thread, soft threshold five, no connection-request queue, and three configured connection retries. These pool/retry values are accepted but not wired to equivalent controls in the current Rust gateway.
  • Forwarding: Host is rewritten for the backend; forwarding metadata is regenerated from the current connection rather than trusting existing values. Discovery hosts remain hostname-based in Java.
  • Routing/adaptation: arbitrary service_url routing is disabled by the empty whitelist, query service-ID override is disabled, and all rewrite collections are empty.
  • Metrics: the declared Java injection flag is off with the default name retained. See the metrics property pages for the current implementation qualification and Rust support.

To allow an explicit host without opening routing to every hostname, replace the empty whitelist with:

hostWhitelist:
  - 'api\.example\.com'

service_url: https://api.example.com:8443/base is then eligible; service_url: https://evil.example.com/base is denied. The pattern does not restrict port or scheme, and it does not validate the target’s certificate.

Streaming examples

SSE subscription with heartbeats

maxRequestTime: 5000
streamPathPrefixes:
  - /events/
streamMaxRequestTime: 0
streamIdleTimeout: 30000

The declared /events/ paths have no total router deadline. Once SSE response headers confirm streaming, a heartbeat every fifteen seconds keeps the thirty-second idle timer alive. Ordinary paths still have five seconds. Keep the default SSE request/response media-type lists and header-overwrite list unless the backend uses different types.

Bounded chat or NDJSON stream

maxRequestTime: 10000
streamResponseContentTypes:
  - text/event-stream
  - application/x-ndjson
streamRequestAcceptTypes:
  - text/event-stream
  - application/x-ndjson
streamPathPrefixes:
  - /v1/chat/stream
streamMaxRequestTime: 120000
streamIdleTimeout: 15000

The chat path starts with a two-minute total budget. Once a recognized streaming response begins, fifteen seconds without bytes closes it. Other requests have a ten-second ordinary budget. A backend returning application/x-ndjson is recognized as streaming as well as one returning SSE. Accept-only classification and response-only deadline switching differ between the runtimes; declaring the actual stream path makes its pre-header intent explicit.

Streaming passthrough does not convert a JSON API into SSE. Confirm that the backend emits incremental bytes, the response chain supports streaming, and any fronting proxy/load balancer permits the intended duration. Rust checks response-handler compatibility for streams; handlers that require complete-body transformations can conflict with passthrough.

Rewrite examples

The individual pages preserve the source template, Java test-fixture, Rust combined-test, and existing-help examples, with explanations of their inputs and results:

  • URL rules: listings to a query-based HTML endpoint, deployment-prefix removal, WordPress-to-CMS file mapping, API-prefix changes, and a Rust combined rewrite under a target base path.
  • Method rules: POST-to-PUT/PATCH and GET-to-DELETE at address/pet endpoints, including the nested pet-address example and the limitations of the old POST-to-GET example.
  • Query rules: rename only, replace value only, both together, multiple rules per endpoint, endpoint placeholders, and YAML/JSON forms.
  • Header rules: the same field transformations, the legacy-token-to-Authorization example, and Java’s request/response copy behavior.
  • Timeout overrides: every address-version timeout, pet identifier correction, long-poll/upload examples, and native/JSON-text map forms.
  • Host allowlist: source subnet-like regex examples, their actual regex meaning, corrected escaped patterns, and allowed/denied hostname examples.

Java and Rust compatibility notes

These findings are based on the source inspected on 2026-10-01. Shared names and defaults do not establish runtime equivalence.

AreaJava light-4jRust light-fabricGuidance
Ordinary default deadline1000 ms0 (disabled)Set maxRequestTime explicitly.
HTTP/2/TLS commentsOlder descriptions mention incoming traffic; handler configures the outbound clientOutbound HTTP/2 negotiation; HTTPS-node filtering and per-target TLSConfigure listeners separately; verify the selected target protocol.
Timeout-prefix overlapFirst matching map entryLongest nonempty prefixAvoid overlaps. Braces are literal in both.
Pool, queue, retry, DNS conversion fieldsUsed by Undertow/router poolAccepted, but no gateway wiring for connectionsPerThread, softMaxConnectionsPerThread, maxQueueSize, maxConnectionRetries, or preResolveFQDN2IPDo not infer Rust limits from these values.
Explicit URL allowlistEmpty list errors/denies routingEmpty list returns forbiddenEmpty means deny explicit URLs, not allow all.
Regex engineJava regexRust regexUse common regex syntax.
Method rule overlapContinues evaluation; utility matcher accepts leading endpoint segmentsFirst complete-pattern matchUse distinct endpoint rules.
Query/header endpoint-map selectionFirst utility matchLongest match, also literal-prefix matchingAvoid overlapping keys and check child paths.
URL replacement introduces queryCan append another ? for an existing queryMerges replacement and incoming query pairsAvoid that combination in portable rules.
Unmatched endpoint with nonempty query rule mapCurrent builder omits original queryOriginal pairs preservedCheck unrelated Java endpoints.
Header rule listApplied to request and response copy; unrelated headers can be omitted and oldK comparison is case-sensitiveRequest only; unrelated headers retainedVerify all required headers in Java.
Query routing-key removalRemoves parsed key, but no-rewrite branch can reuse original query stringRemoves routing pair while rebuilding upstream URICheck Java wire behavior.
Accept-only expected streamUses streaming budget immediatelyKeeps ordinary budget until response confirms streamingSet an ordinary setup deadline and declare known streaming paths.
Response-only streamCancels ordinary timer without installing a new positive streaming total timerSwitches to streaming budget measured from request startSee streamMaxRequestTime.
Named downstream metric injectionUses available Java metrics handler; current request path can look it up even with flag falseFlags/name accepted, not used for Java-style injectionCheck the runtime’s actual metrics configuration.

The common examples describe intended results for unambiguous, single-valued inputs. Multivalue queries/headers, colliding destination keys, overlapping endpoints, protocol/TLS choices, and combinations of rewrites need verification on the target runtime. This documentation change does not change either router implementation.

Troubleshooting

SymptomWhat to check
Explicit service_url failsWhitelist is nonempty, regex matches the hostname as a whole, and URL is valid. Rust rejects user info, query, and fragments in a target URL.
Wrong service selectedQuery service_id override, explicit service_url precedence, earlier path/service mappings, and env_tag.
Ordinary API times outExplicit global value, literal prefix matches, backend duration, and independent connect/client/load-balancer timeouts.
Stream closes too earlyCorrect response Content-Type, known streaming path, total/idle budgets, heartbeat gaps, handler-chain compatibility, and external proxy limits.
Pet timeout override does not workUse /v1/pets/; timeout-prefix matching does not interpret {petId}.
Rewrite does not matchDistinguish literal prefix, endpoint placeholder, and whole-path regex syntax; check casing and escape characters.
Query/header disappears in JavaCheck nonmatching query-map behavior and copyHeaders with nonempty header rules, as described above.
Pool or retry setting has no effect in RustThose fields are currently parsed compatibility settings, not wired Pingora controls.
Metrics do not follow the flag/nameConfirm Java metrics-handler presence or Rust’s separate metrics implementation.

Sources and Portal catalog evidence

This reference reconciles the templates, implementation, tests, and the read-only local configserver catalog. The catalog contains one Router description and 19 Router property descriptions; it does not yet contain the six streaming properties present in current Java/Rust source. Its maxRequestTime default is 1000. Descriptions are treated as authoring guidance; executable source takes precedence where an old description is inaccurate.

Java sources reviewed at light-4j revision ce59ecae5:

Rust sources reviewed at light-fabric revision a6b39d4:

These are source and catalog findings, not a claim that the examples have all been exercised against a deployed Java and Rust gateway. Recheck implementation qualifications when upgrading either runtime.