[nextjs] Fix proxy chain clobbering redirects in multi-language sites#457
Open
RobertoArmas wants to merge 2 commits intoSitecore:devfrom
Open
[nextjs] Fix proxy chain clobbering redirects in multi-language sites#457RobertoArmas wants to merge 2 commits intoSitecore:devfrom
RobertoArmas wants to merge 2 commits intoSitecore:devfrom
Conversation
Co-authored-by: Copilot <copilot@github.com>
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.
Description / Motivation
Fixes a bug in multi-language sites where redirects produced by an earlier proxy in the chain were being clobbered by subsequent proxies.
defineProxy(...).exec(...)runs registered proxy handlers (locale,multisite,redirects,personalize, etc.) sequentially against a sharedNextResponse.Previously, when one of those handlers issued a redirect by setting the
locationheader on the response, the remaining handlers in the chain still executed and could mutate the response (rewrite path, change or append headers, overwrite cookies), which in some scenarios resulted in the redirect being lost or the user landing on the wrong locale URL.This PR makes
defineProxyshort-circuit the chain as soon as the response carries alocationheader, so once a proxy decides to redirect, downstream handlers are skipped and the redirect is preserved as-is.The change is scoped to
packages/nextjs/src/proxy/proxy.tsand is non-breaking: the chain continues to execute fully whenever nolocationheader is set, which remains the existing default case.Real-world use case: composing
next-intlwith the Content SDK proxyA common multi-language setup is to compose
next-intl's proxy / middleware with the Content SDK proxy chain in a singleproxy.ts(formerlymiddleware.tsbefore Next.js 16).next-intlperforms locale negotiation based on prefix, cookie, and theaccept-languageheader, and on the very first hit it typically produces a redirect (for example,/→/en, orus.example.com/fr→ca.example.com/frfor domain-based routing). That redirect is expressed by setting thelocationheader on theNextResponseit returns.With the current SDK, this composition does not work out of the box: the Content SDK proxies registered after
NextIntlProxykeep executing on top of the already-redirecting response and clobber thelocationheader.To work around this, projects today have to fork
defineProxylocally just to add alocation-header short-circuit — exactly the change this PR merges upstream.A real consumer's
proxy.tsin this state currently looks like this:Before this fix: when the user requests /, NextIntlProxy returns a 307 Location: /en. Without the short-circuit, LocaleProxy, AppRouterMultisiteProxy, RedirectsProxy, PersonalizeProxy and CSPProxy still run on top of that response, mutate it (rewrite URL, set cookies, set headers) and the location header gets effectively lost — the browser ends up not being redirected to the localized URL on the first hit, and locale negotiation appears broken.
After this fix: defineProxy itself stops the chain as soon as a location header is present on the response, so the next-intl redirect reaches the browser intact. Consumers can drop customDefineProxy and use defineProxy from @sitecore-content-sdk/nextjs/proxy directly:
The same situation applies to any composition where an upstream step (auth guard, tenant resolver, custom locale logic, or the SDK's own RedirectsProxy) issues a redirect before later proxies in the chain run.
Testing Details
packages/nextjs/src/proxy/proxy.test.ts:defineProxy > should stop executing proxies when a previous proxy sets location header— verifies that handlers registered after a redirecting handler are not
invoked and that the
locationheader on the resulting response ispreserved.
defineProxytests (chain order, empty response, Next.js 16 styleexec(req)withoutNextFetchEvent) continue to pass, confirming thenon-redirect path is unchanged.
redirects-proxy issues a 301/302 to a localized URL; before the fix the
redirect was being overwritten by the following proxy, after the fix the
browser receives the intended redirect.
Types of changes