SSR resolves relative `redirectTo` against the wrong base when the route path has several segments
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 45/100
調査の方向性
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.
索引モデルが issue の本文から書いたものです。
説明
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.
- 主要言語
- TypeScript
- スター
- 27k
- フォーク
- 11.8k
- 平均マージ
- 1日 1時間
- マージ済み PR(30日)
- 161
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
angular/angular-cli のほかの issue
-
area: @angular/build gemini-triaged
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
angular/angular-cli#33955 ·
メンテナーはふだん 1 日以内に返信
-
area: @angular/cli gemini-triaged
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
angular/angular-cli#33055 · コメント 1 件 · リアクション 3 件 ·
メンテナーはふだん 1 日以内に返信
-
SSR route redirects drop the query string on relative `redirectTo`対応中かも @bschaeublin が 2 日前に担当しました。 オープンarea: @angular/ssr
難易度 3/5 1〜2日 初心者へのやさしさ 45/100
angular/angular-cli#34298 ·
メンテナーはふだん 1 日以内に返信
-
area: @angular/build
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
angular/angular-cli#34292 ·
メンテナーはふだん 1 日以内に返信
-
dev-server: es2016 prebundle target for zone.js apps lowers private fields and breaks dependenciesオープンarea: @angular/build
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
angular/angular-cli#34280 ·
メンテナーはふだん 1 日以内に返信
angular/angular-cli の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
cline/mcp-marketplace#2932 ·
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
lingdojo/kana-dojo#32188 · コメント 1 件 · リアクション 5 件 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
Portkey-AI/gateway#1844 ·
メンテナーはふだん 1 日以内に返信
-
needs triage
難易度 2/5 1〜3時間 初心者へのやさしさ 61/100
rjsf-team/react-jsonschema-form#5495 ·
メンテナーはふだん 2 日以内に返信