Skip to content

Commit 2496604

Browse files
committed
fix(@angular/ssr): preserve response headers during redirect
Previously, when a redirect was triggered, any custom headers (such as cookies or cache control) configured on the RESPONSE_INIT object by components or guards were lost because the redirect response was created with the default headers only. Closes #33473
1 parent 010cef6 commit 2496604

3 files changed

Lines changed: 11 additions & 4 deletions

File tree

packages/angular/ssr/src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ export class AngularServerApp {
353353
}
354354

355355
if (result.redirectTo) {
356-
return createRedirectResponse(result.redirectTo, responseInit.status, headers);
356+
return createRedirectResponse(result.redirectTo, responseInit.status, responseInit.headers);
357357
}
358358

359359
if (renderMode === RenderMode.Prerender) {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
/**
1010
* An set of HTTP status codes that are considered valid for redirect responses.
1111
*/
12-
export const VALID_REDIRECT_RESPONSE_CODES: Set<number> = new Set([301, 302, 303, 307, 308]);
12+
export const VALID_REDIRECT_RESPONSE_CODES: ReadonlySet<number> = new Set([
13+
301, 302, 303, 307, 308,
14+
]);
1315

1416
/**
1517
* Checks if the given HTTP status code is a valid redirect response code.
@@ -33,7 +35,7 @@ export function isValidRedirectResponseCode(code: number): boolean {
3335
export function createRedirectResponse(
3436
location: string,
3537
status = 302,
36-
headers?: Record<string, string>,
38+
headers?: Record<string, string> | Headers,
3739
): Response {
3840
if (ngDevMode && !isValidRedirectResponseCode(status)) {
3941
throw new Error(
@@ -42,7 +44,7 @@ export function createRedirectResponse(
4244
);
4345
}
4446

45-
const resHeaders = new Headers(headers);
47+
const resHeaders = headers instanceof Headers ? headers : new Headers(headers);
4648
if (ngDevMode && resHeaders.has('location')) {
4749
// eslint-disable-next-line no-console
4850
console.warn(

packages/angular/ssr/test/app_spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ describe('AngularServerApp', () => {
4242
const responseInit = inject(RESPONSE_INIT);
4343
if (responseInit) {
4444
responseInit.status = 308;
45+
const headers = responseInit.headers;
46+
if (headers) {
47+
(headers as Headers).set('X-Redirect-Header', 'custom-value');
48+
}
4549
}
4650

4751
void inject(Router).navigate([], {
@@ -326,6 +330,7 @@ describe('AngularServerApp', () => {
326330
const response = await app.handle(new Request('http://localhost/redirect-via-navigate'));
327331
expect(response?.headers.get('location')).toBe('/redirect-via-navigate?filter=test');
328332
expect(response?.status).toBe(308);
333+
expect(response?.headers.get('X-Redirect-Header')).toBe('custom-value');
329334
});
330335

331336
it('returns a 302 status and redirects to the correct location when `urlTree` is updated in a guard', async () => {

0 commit comments

Comments
 (0)