Skip to content

Commit

Permalink
perf(http): reduce data transfer when using HTTP caching (#52347)
Browse files Browse the repository at this point in the history
This commit reduces the property size in the http transfer cache to reduce the page payload.

Before
```html
<script id="ng-state" type="application/json">
{
  "4155228514": {
    "body": "....",
    "headers": {},
    "status": 200,
    "statusText": "OK",
    "url": "http://foo.com/assets/media.json",
    "responseType": "json"
  },
}
</script>
```

Now
```html
<script id="ng-state" type="application/json">
{
  "4155228514": {
    "b": "....",
    "h": {},
    "s": 200,
    "st": "OK",
    "u": "http://foo.com/assets/media.json",
    "rt": "json"
  },
}
</script>
```

PR Close #52347
  • Loading branch information
alan-agius4 authored and dylhunn committed Oct 24, 2023
1 parent 4e00851 commit bd9e91e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 34 deletions.
66 changes: 46 additions & 20 deletions packages/common/http/src/transfer_cache.ts
Expand Up @@ -35,13 +35,31 @@ export type HttpTransferCacheOptions = {
includePostRequests?: boolean
};

/**
* Keys within cached response data structure.
*/

export const BODY = 'b';
export const HEADERS = 'h';
export const STATUS = 's';
export const STATUS_TEXT = 'st';
export const URL = 'u';
export const RESPONSE_TYPE = 'rt';


interface TransferHttpResponse {
body: any;
headers: Record<string, string[]>;
status?: number;
statusText?: string;
url?: string;
responseType?: HttpRequest<unknown>['responseType'];
/** body */
[BODY]: any;
/** headers */
[HEADERS]: Record<string, string[]>;
/** status */
[STATUS]?: number;
/** statusText */
[STATUS_TEXT]?: string;
/** url */
[URL]?: string;
/** responseType */
[RESPONSE_TYPE]?: HttpRequest<unknown>['responseType'];
}

interface CacheOptions extends HttpTransferCacheOptions {
Expand Down Expand Up @@ -82,22 +100,30 @@ export function transferCacheInterceptorFn(
}

if (response) {
const {
[BODY]: undecodedBody,
[RESPONSE_TYPE]: responseType,
[HEADERS]: httpHeaders,
[STATUS]: status,
[STATUS_TEXT]: statusText,
[URL]: url
} = response;
// Request found in cache. Respond using it.
let body: ArrayBuffer|Blob|string|undefined = response.body;
let body: ArrayBuffer|Blob|string|undefined = undecodedBody;

switch (response.responseType) {
switch (responseType) {
case 'arraybuffer':
body = new TextEncoder().encode(response.body).buffer;
body = new TextEncoder().encode(undecodedBody).buffer;
break;
case 'blob':
body = new Blob([response.body]);
body = new Blob([undecodedBody]);
break;
}

// We want to warn users accessing a header provided from the cache
// That HttpTransferCache alters the headers
// The warning will be logged a single time by HttpHeaders instance
let headers = new HttpHeaders(response.headers);
let headers = new HttpHeaders(httpHeaders);
if (typeof ngDevMode === 'undefined' || ngDevMode) {
// Append extra logic in dev mode to produce a warning when a header
// that was not transferred to the client is accessed in the code via `get`
Expand All @@ -110,9 +136,9 @@ export function transferCacheInterceptorFn(
new HttpResponse({
body,
headers,
status: response.status,
statusText: response.statusText,
url: response.url,
status,
statusText,
url,
}),
);
}
Expand All @@ -123,12 +149,12 @@ export function transferCacheInterceptorFn(
tap((event: HttpEvent<unknown>) => {
if (event instanceof HttpResponse) {
transferState.set<TransferHttpResponse>(storeKey, {
body: event.body,
headers: getFilteredHeaders(event.headers, headersToInclude),
status: event.status,
statusText: event.statusText,
url: event.url || '',
responseType: req.responseType,
[BODY]: event.body,
[HEADERS]: getFilteredHeaders(event.headers, headersToInclude),
[STATUS]: event.status,
[STATUS_TEXT]: event.statusText,
[URL]: event.url || '',
[RESPONSE_TYPE]: req.responseType,
});
}
}),
Expand Down
28 changes: 14 additions & 14 deletions packages/common/http/test/transfer_cache_spec.ts
Expand Up @@ -14,7 +14,7 @@ import {withBody} from '@angular/private/testing';
import {BehaviorSubject} from 'rxjs';

import {HttpClient, HttpResponse, provideHttpClient} from '../public_api';
import {withHttpTransferCache} from '../src/transfer_cache';
import {BODY, HEADERS, RESPONSE_TYPE, STATUS, STATUS_TEXT, URL, withHttpTransferCache} from '../src/transfer_cache';
import {HttpTestingController, provideHttpClientTesting} from '../testing';

interface RequestParams {
Expand Down Expand Up @@ -84,7 +84,7 @@ describe('TransferCache', () => {
makeRequestAndExpectOne('/test', 'foo');
const key = makeStateKey('432906284');
const transferState = TestBed.inject(TransferState);
expect(transferState.get(key, null)).toEqual(jasmine.objectContaining({body: 'foo'}));
expect(transferState.get(key, null)).toEqual(jasmine.objectContaining({[BODY]: 'foo'}));
});

it('should stop storing HTTP calls in `TransferState` after application becomes stable',
Expand All @@ -101,20 +101,20 @@ describe('TransferCache', () => {
const transferState = TestBed.inject(TransferState);
expect(JSON.parse(transferState.toJson()) as Record<string, unknown>).toEqual({
'3706062792': {
'body': 'foo',
'headers': {},
'status': 200,
'statusText': 'OK',
'url': '/test-1',
'responseType': 'json'
[BODY]: 'foo',
[HEADERS]: {},
[STATUS]: 200,
[STATUS_TEXT]: 'OK',
[URL]: '/test-1',
[RESPONSE_TYPE]: 'json'
},
'3706062823': {
'body': 'buzz',
'headers': {},
'status': 200,
'statusText': 'OK',
'url': '/test-2',
'responseType': 'json'
[BODY]: 'buzz',
[HEADERS]: {},
[STATUS]: 200,
[STATUS_TEXT]: 'OK',
[URL]: '/test-2',
[RESPONSE_TYPE]: 'json'
}
});
}));
Expand Down
18 changes: 18 additions & 0 deletions packages/core/test/bundling/hydration/bundle.golden_symbols.json
Expand Up @@ -32,6 +32,9 @@
{
"name": "BLOOM_MASK"
},
{
"name": "BODY"
},
{
"name": "BROWSER_MODULE_PROVIDERS"
},
Expand Down Expand Up @@ -188,6 +191,9 @@
{
"name": "HAS_TRANSPLANTED_VIEWS"
},
{
"name": "HEADERS"
},
{
"name": "HTTP_ROOT_INTERCEPTOR_FNS"
},
Expand Down Expand Up @@ -398,6 +404,9 @@
{
"name": "REMOVE_STYLES_ON_COMPONENT_DESTROY"
},
{
"name": "RESPONSE_TYPE"
},
{
"name": "RefCountOperator"
},
Expand Down Expand Up @@ -425,6 +434,12 @@
{
"name": "SKIP_HYDRATION_ATTR_NAME_LOWER_CASE"
},
{
"name": "STATUS"
},
{
"name": "STATUS_TEXT"
},
{
"name": "SafeSubscriber"
},
Expand Down Expand Up @@ -500,6 +515,9 @@
{
"name": "TransferState"
},
{
"name": "URL2"
},
{
"name": "USE_VALUE"
},
Expand Down

0 comments on commit bd9e91e

Please sign in to comment.