Documentation Index
Fetch the complete documentation index at: https://mintlify.com/nodejs/undici/llms.txt
Use this file to discover all available pages before exploring further.
RedirectHandler and DecoratorHandler are two low-level handler classes that underpin undici’s redirect infrastructure and the interceptor system. RedirectHandler intercepts 3xx responses and re-dispatches the request to the new Location, while DecoratorHandler provides a pass-through base class for building handler middleware without losing any lifecycle events.
RedirectHandler
RedirectHandler implements all dispatch handler methods. When it receives a 3xx response with a Location header, it silently discards the redirect body, updates the request options to target the new URL, and calls dispatch again — repeating until the response is not a redirect or the redirect limit is reached.
Under normal usage you won’t construct RedirectHandler directly. The interceptors.redirect interceptor creates one automatically for every request. Direct instantiation is useful when you need to embed redirect-following logic within a custom handler pipeline without adding a dispatcher-level interceptor.
Constructor
The dispatch function to invoke for each redirect hop. This is typically
client.dispatch.bind(client) or a wrapped version that goes through your existing interceptor stack.Maximum number of redirects to follow. Must be a non-negative integer. When the history length reaches this value, the interceptor stops redirecting: if
opts.throwOnMaxRedirect is true, an error is thrown; otherwise the final 3xx response is forwarded to the handler.Standard dispatch options for the initial request.
RedirectHandler mutates a copy of this object on each hop to update path, origin, method, and headers.The downstream handler that receives the final (non-redirect) response events.
Properties
| Property | Type | Description |
|---|---|---|
location | string | null | The Location header value of the most recent 3xx response, or null when not redirecting |
opts | object | Current request options, updated on each redirect hop |
maxRedirections | number | The configured maximum redirect count |
handler | object | The wrapped downstream handler |
history | URL[] | Array of URLs visited during the redirect chain |
Redirect method and body rules
The handler strictly follows RFC 7231 and the Fetch specification:| Status | Original method | New method | Body |
|---|---|---|---|
| 301, 302 | POST | GET | Dropped |
| 301, 302 | Any other | Unchanged | Preserved |
| 303 | Any (except HEAD) | GET | Dropped |
| 307, 308 | Any | Unchanged | Preserved |
| 300 | Any | Unchanged | Discarded (ignored) |
Redirect loop detection
RedirectHandler keeps a history array of visited URLs. Before following each redirect it checks whether the new Location is already in the history. If so, it throws an InvalidArgumentError with a message indicating a redirect loop was detected.
Header stripping on redirect
The handler automatically removes sensitive headers in specific scenarios:host— always removed and replaced with the redirect target’s host.content-*headers — removed on303redirects (because the method changes toGET).authorization,cookie,proxy-authorization— removed when the redirect crosses an origin boundary (different scheme or host).
Handler methods
RedirectHandler implements the full Dispatcher.DispatchHandler interface. Most methods delegate to the wrapped handler, but onResponseStart, onResponseData, and onResponseEnd contain the redirect interception logic.
onRequestStart(controller, context)
Forwards to the inner handler, augmenting context with a history property containing the redirect chain so far.
onResponseStart(controller, statusCode, headers, statusMessage)
The core of redirect logic. When statusCode is in [300, 301, 302, 303, 307, 308] and headers.location is present, this method updates opts for the next hop and records the current URL in history. If not redirecting, it forwards directly to the wrapped handler.
onResponseData(controller, chunk)
When a redirect is in progress, the body chunk is silently discarded. Otherwise the chunk is forwarded to the wrapped handler.
onResponseEnd(controller, trailers)
When a redirect is in progress, triggers the next dispatch instead of forwarding onResponseEnd. When not redirecting, forwards to the wrapped handler.
onResponseError(controller, error)
Always forwarded to the wrapped handler.
onRequestUpgrade(controller, statusCode, headers, socket)
Forwarded to the wrapped handler.
Comparing RedirectHandler to interceptors.redirect
RedirectHandler directly only when you need to compose it manually — for example, to share a history array across multiple dispatches or to embed redirect logic inside another handler class.
Examples
- Via interceptor (recommended)
- Manual RedirectHandler
Redirect following via interceptors.redirect
DecoratorHandler
DecoratorHandler is the base class for handler middleware in undici. It wraps an inner handler and forwards every lifecycle method call to it unchanged, adding internal invariant assertions to catch incorrect handler usage (e.g. receiving data after completion, or completing twice).
Constructor
The handler object to delegate to. Must be a non-null object; throws
TypeError otherwise.Methods
All methods are optional on the inner handler (called with optional chaining).DecoratorHandler adds assert guards to enforce the correct event ordering mandated by the dispatch protocol.
| Method | Assertion | Forwards to |
|---|---|---|
onRequestStart(controller, context) | None | handler.onRequestStart?.() |
onRequestUpgrade(controller, statusCode, headers, socket) | Not completed, not errored | handler.onRequestUpgrade?.() |
onResponseStart(controller, statusCode, headers, statusMessage) | Not completed, not errored, not called before | handler.onResponseStart?.() |
onResponseData(controller, chunk) | Not completed, not errored | handler.onResponseData?.() |
onResponseEnd(controller, trailers) | Not completed, not errored | handler.onResponseEnd?.() |
onResponseError(controller, err) | None | handler.onResponseError?.() |
onBodySent() | — | No-op (deprecated) |
Subclassing DecoratorHandler
To intercept a specific lifecycle event, override the corresponding method, perform your logic, and call super.method() to delegate to the wrapped handler.
Custom handler that measures response time
Using DecoratorHandler alongside RedirectHandler
RedirectHandler does not extend DecoratorHandler — it implements the handler interface directly. However, you can combine both: wrap a DecoratorHandler subclass with a RedirectHandler to get redirect-following plus custom interception at the same time.
RedirectHandler wrapping a DecoratorHandler subclass