SSR resolves relative `redirectTo` against the wrong base when the route path has several segments
维护者通常 1 天内回复
已经有一个关联 PR 被合并了。
- #34301 来自 @bschaeublin —— 已合并
评估
- 难度
- 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 天 2 小时
- 30 天内合并 PR
- 156
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
angular/angular-cli 的其他 Issue
-
area: @angular/cli
难度 2/5 1-3 小时 新手友好度 78/100
angular/angular-cli#34307 ·
维护者通常 1 天内回复
-
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 个 reaction ·
维护者通常 1 天内回复
-
@angular/ssr: page under nested empty-path routes is prerendered without the modulepreload hints of its lazy chunks (regression since 19.1.6)可能已有人在做 @alan-agius4 今天认领。 未关闭area: @angular/ssr
angular/angular-cli#34320 · 已指派 1 人 ·
维护者通常 1 天内回复
-
area: @angular/build
难度 4/5 3-5 天 新手友好度 48/100
angular/angular-cli#34312 ·
维护者通常 1 天内回复
查看 angular/angular-cli 的全部 Issue
相似的 Issue
-
affected/v17 affected/v18 area/frontend type/bug
难度 2/5 1-3 小时 新手友好度 82/100
umbraco/Umbraco-CMS#24186 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
better-auth/better-auth#11723 · 1 个 reaction ·
维护者通常 1 天内回复
-
area: docs difficulty: easy documentation good first issue
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
Worker-Erstellung bricht langsame Git-Worktree-Checkouts nach 20 Sekunden ab可能已有人在做 @KajoVanBuyten 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 69/100
AgentSystemLabs/agent-office#367 ·
维护者通常 1 天内回复