Skip to content

Commit 3a28fb6

Browse files
committed
fix(@angular/ssr): correctly handle routes with matrix parameters
This commit introduces a change to strip matrix parameters from the URL before route matching in Angular SSR. Previously, URLs containing matrix parameters would fail to match their corresponding routes. A new `stripMatrixParams` utility function has been added to remove these parameters, ensuring that route matching is not affected by their presence. Closes #31457 (cherry picked from commit 85c18b4)
1 parent f7bd567 commit 3a28fb6

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

packages/angular/ssr/src/routes/router.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import { AngularAppManifest } from '../manifest';
10-
import { stripIndexHtmlFromURL } from '../utils/url';
10+
import { stripIndexHtmlFromURL, stripMatrixParams } from '../utils/url';
1111
import { extractRoutesAndCreateRouteTree } from './ng-routes';
1212
import { RouteTree, RouteTreeNodeMetadata } from './route-tree';
1313

@@ -85,8 +85,10 @@ export class ServerRouter {
8585
match(url: URL): RouteTreeNodeMetadata | undefined {
8686
// Strip 'index.html' from URL if present.
8787
// A request to `http://www.example.com/page/index.html` will render the Angular route corresponding to `http://www.example.com/page`.
88-
const { pathname } = stripIndexHtmlFromURL(url);
88+
let { pathname } = stripIndexHtmlFromURL(url);
89+
pathname = stripMatrixParams(pathname);
90+
pathname = decodeURIComponent(pathname);
8991

90-
return this.routeTree.match(decodeURIComponent(pathname));
92+
return this.routeTree.match(pathname);
9193
}
9294
}

packages/angular/ssr/src/utils/url.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,27 @@ export function buildPathWithParams(toPath: string, fromPath: string): string {
196196

197197
return joinUrlParts(...resolvedParts);
198198
}
199+
200+
const MATRIX_PARAMS_REGEX = /;[^/]+/g;
201+
202+
/**
203+
* Removes Angular matrix parameters from a given URL path.
204+
*
205+
* This function takes a URL path string and removes any matrix parameters.
206+
* Matrix parameters are parts of a URL segment that start with a semicolon `;`.
207+
*
208+
* @param pathname - The URL path to remove matrix parameters from.
209+
* @returns The URL path with matrix parameters removed.
210+
*
211+
* @example
212+
* ```ts
213+
* stripMatrixParams('/path;param=value'); // returns '/path'
214+
* stripMatrixParams('/path;param=value/to;p=1/resource'); // returns '/path/to/resource'
215+
* stripMatrixParams('/path/to/resource'); // returns '/path/to/resource'
216+
* ```
217+
*/
218+
export function stripMatrixParams(pathname: string): string {
219+
// Use a regular expression to remove matrix parameters.
220+
// This regex finds all occurrences of a semicolon followed by any characters
221+
return pathname.includes(';') ? pathname.replace(MATRIX_PARAMS_REGEX, '') : pathname;
222+
}

packages/angular/ssr/test/utils/url_spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
joinUrlParts,
1414
stripIndexHtmlFromURL,
1515
stripLeadingSlash,
16+
stripMatrixParams,
1617
stripTrailingSlash,
1718
} from '../../src/utils/url';
1819

@@ -181,4 +182,30 @@ describe('URL Utils', () => {
181182
}).toThrowError(`Invalid toPath: The string must start with a '/'. Received: 'details'`);
182183
});
183184
});
185+
186+
describe('stripMatrixParams', () => {
187+
it('should remove a single matrix parameter', () => {
188+
expect(stripMatrixParams('/path;param=value')).toBe('/path');
189+
});
190+
191+
it('should remove multiple matrix parameters in the same segment', () => {
192+
expect(stripMatrixParams('/path;p1=v1;p2=v2')).toBe('/path');
193+
});
194+
195+
it('should remove matrix parameters from multiple segments', () => {
196+
expect(stripMatrixParams('/path;p1=v1/to;p2=v2/resource')).toBe('/path/to/resource');
197+
});
198+
199+
it('should not modify a path without matrix parameters', () => {
200+
expect(stripMatrixParams('/path/to/resource')).toBe('/path/to/resource');
201+
});
202+
203+
it('should handle a root path with matrix parameters', () => {
204+
expect(stripMatrixParams('/;p1=v1')).toBe('/');
205+
});
206+
207+
it('should handle an empty string', () => {
208+
expect(stripMatrixParams('')).toBe('');
209+
});
210+
});
184211
});

0 commit comments

Comments
 (0)