SSR resolves relative `redirectTo` against the wrong base when the route path has several segments
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 45/100
Direzione di ricerca
The bug sits in resolveRedirectTo in packages/angular/ssr/src/routes/ng-routes.ts, which pops only the last segment where the router replaces all segments the route consumes. Start by reading that function, then the redirect/relative case in packages/angular/ssr/test/app_spec.ts. Done means a multi-segment relative redirectTo resolves to the router's result, with the two existing app_spec expectations updated. The issue author already has a fix and PR planned, and it changes current behaviour, so coordinate with them first.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Command
other
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
No response
Description
When a request matches a route with a string redirectTo, @angular/ssr answers with a 302 built from the route config, without running the router. If the route's own path has more than one segment, a relative redirectTo is resolved against the wrong base.
{ path: 'old/page', redirectTo: 'new/page' }:
- Server:
GET /old/pagereturnsLocation: /old/new/page(a 404). - Router (in-app navigation to
/old/page):/new/page.
The router replaces all segments matched by the redirecting route (old/page). The server only removes the last one (page). Routes whose path is a single segment or empty are not affected, which is probably why this has gone unnoticed.
Note: fixing this changes current behaviour. app_spec.ts asserts the current result (L207-L217: redirect/relative → /redirect/home, the router gives /home), and an app could depend on it if it happens to have a route at the server-computed path.
Minimal Reproduction
npx @angular/[email protected] new repro-app --ssr --defaults
cd repro-app
src/app/app.routes.ts:
import { Component } from '@angular/core';
import { Routes } from '@angular/router';
@Component({ template: 'New page' })
class NewPage {}
export const routes: Routes = [
{ path: 'old/page', redirectTo: 'new/page' },
{ path: 'new/page', component: NewPage },
];
src/app/app.routes.server.ts (server rendering, so the request reaches the redirect handling instead of a prerendered redirect page):
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [{ path: '**', renderMode: RenderMode.Server }];
npx ng build
NG_ALLOWED_HOSTS=localhost PORT=4000 node dist/repro-app/server/server.mjs
curl -si 'localhost:4000/old/page' | grep -i '^location'
Expected: location: /new/page (where the router navigates). Actual: location: /old/new/page.
Exception or Error
$ curl -si localhost:4000/old/page | head -3
HTTP/1.1 302 Found
X-Powered-By: Express
location: /old/new/page
Your Environment
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 22.2.2
Angular : 22.2.2
Node.js : 24.18.0
Package Manager : npm 11.16.0
Operating System : linux x64
┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build │ 22.2.2 │ ^22.2.2 │
│ @angular/cli │ 22.2.2 │ ^22.2.2 │
│ @angular/common │ 22.2.2 │ ^22.2.0 │
│ @angular/compiler │ 22.2.2 │ ^22.2.0 │
│ @angular/compiler-cli │ 22.2.2 │ ^22.2.0 │
│ @angular/core │ 22.2.2 │ ^22.2.0 │
│ @angular/forms │ 22.2.2 │ ^22.2.0 │
│ @angular/platform-browser │ 22.2.2 │ ^22.2.0 │
│ @angular/platform-server │ 22.2.2 │ ^22.2.0 │
│ @angular/router │ 22.2.2 │ ^22.2.0 │
│ @angular/ssr │ 22.2.2 │ ^22.2.2 │
│ rxjs │ 7.8.2 │ ~7.8.0 │
│ typescript │ 6.0.3 │ ~6.0.2 │
└───────────────────────────┴───────────────────┴───────────────────┘
Anything else relevant?
resolveRedirectTo in ng-routes.ts#L543-L554 removes one segment (segments.pop()), while the router's applyRedirectCommands replaces all segments consumed by the route.
Related: #33504 / #33516 (parameters in the same function).
I have a fix with tests and will open a PR for it. It updates the two app_spec expectations above to the router's result. If the current behaviour is intended, or this should wait for a major, I'm happy to adjust.
Not browser specific. Seen with the default Express server.ts generated by ng new --ssr; the redirect comes from AngularNodeAppEngine.handle(), not from Express itself.
- Lingua principale
- TypeScript
- Stelle
- 27k
- Fork
- 11.8k
- Merge medio
- 1g 1h
- PR unite (30g)
- 161
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di angular/angular-cli
-
area: @angular/build gemini-triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
angular/angular-cli#33955 ·
I maintainer di solito rispondono entro 1 giorno
-
area: @angular/cli gemini-triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
angular/angular-cli#33055 · 1 commento · 3 reazioni ·
I maintainer di solito rispondono entro 1 giorno
-
SSR route redirects drop the query string on relative `redirectTo`Forse già presa @bschaeublin l’ha presa 2 giorni fa. Apertaarea: @angular/ssr
Difficoltà 3/5 1-2 giorni Idoneità per principianti 45/100
angular/angular-cli#34298 ·
I maintainer di solito rispondono entro 1 giorno
-
area: @angular/build
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
angular/angular-cli#34292 ·
I maintainer di solito rispondono entro 1 giorno
-
dev-server: es2016 prebundle target for zone.js apps lowers private fields and breaks dependenciesApertaarea: @angular/build
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
angular/angular-cli#34280 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di angular/angular-cli
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
feat(icons): add [solidping]Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
homarr-labs/dashboard-icons#2939 ·
I maintainer di solito rispondono entro 1 giorno
-
Agent/category reasoning variants are still checked against the stale model cache in chat.paramsApertaopencode
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
code-yeongyu/oh-my-openagent#10003 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
I maintainer di solito rispondono entro 1 giorno
-
Actions on ToastsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
nextcloud-libraries/nextcloud-dialogs#2669 ·
I maintainer di solito rispondono entro 1 giorno