Skip to content

Commit

Permalink
Merge pull request DSpace#2304 from 4Science/cache-response-headers
Browse files Browse the repository at this point in the history
Add possibility to store response's headers into the SSR cache
  • Loading branch information
tdonohue authored Jun 14, 2023
2 parents 0c9baf2 + 2f06a7c commit 7ebdcd3
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 5 deletions.
37 changes: 32 additions & 5 deletions server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { buildAppConfig } from './src/config/config.server';
import { APP_CONFIG, AppConfig } from './src/config/app-config.interface';
import { extendEnvironmentWithAppConfig } from './src/config/config.util';
import { logStartupMessage } from './startup-message';
import { TOKENITEM } from 'src/app/core/auth/models/auth-token-info.model';
import { TOKENITEM } from './src/app/core/auth/models/auth-token-info.model';


/*
Expand Down Expand Up @@ -374,9 +374,19 @@ function cacheCheck(req, res, next) {
}

// If cached copy exists, return it to the user.
if (cachedCopy) {
if (cachedCopy && cachedCopy.page) {
if (cachedCopy.headers) {
Object.keys(cachedCopy.headers).forEach((header) => {
if (cachedCopy.headers[header]) {
if (environment.cache.serverSide.debug) {
console.log(`Restore cached ${header} header`);
}
res.setHeader(header, cachedCopy.headers[header]);
}
});
}
res.locals.ssr = true; // mark response as SSR-generated (enables text compression)
res.send(cachedCopy);
res.send(cachedCopy.page);

// Tell Express to skip all other handlers for this path
// This ensures we don't try to re-render the page since we've already returned the cached copy
Expand Down Expand Up @@ -452,21 +462,38 @@ function saveToCache(req, page: any) {
// Avoid caching "/reload/[random]" paths (these are hard refreshes after logout)
if (key.startsWith('/reload')) { return; }

// Retrieve response headers to save, if any
const headers = retrieveHeaders(req.res);
// If bot cache is enabled, save it to that cache if it doesn't exist or is expired
// (NOTE: has() will return false if page is expired in cache)
if (botCacheEnabled() && !botCache.has(key)) {
botCache.set(key, page);
botCache.set(key, { page, headers });
if (environment.cache.serverSide.debug) { console.log(`CACHE SAVE FOR ${key} in bot cache.`); }
}

// If anonymous cache is enabled, save it to that cache if it doesn't exist or is expired
if (anonymousCacheEnabled() && !anonymousCache.has(key)) {
anonymousCache.set(key, page);
anonymousCache.set(key, { page, headers });
if (environment.cache.serverSide.debug) { console.log(`CACHE SAVE FOR ${key} in anonymous cache.`); }
}
}
}

function retrieveHeaders(response) {
const headers = Object.create({});
if (Array.isArray(environment.cache.serverSide.headers) && environment.cache.serverSide.headers.length > 0) {
environment.cache.serverSide.headers.forEach((header) => {
if (response.hasHeader(header)) {
if (environment.cache.serverSide.debug) {
console.log(`Save ${header} header to cache`);
}
headers[header] = response.getHeader(header);
}
});
}

return headers;
}
/**
* Whether a user is authenticated or not
*/
Expand Down
2 changes: 2 additions & 0 deletions src/config/cache-config.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export interface CacheConfig extends Config {
serverSide: {
// Debug server-side caching. Set to true to see cache hits/misses/refreshes in console logs.
debug: boolean,
// List of response headers to save into the cache
headers: string[],
// Cache specific to known bots. Allows you to serve cached contents to bots only.
botCache: {
// Maximum number of pages (rendered via SSR) to cache. Setting max=0 disables the cache.
Expand Down
2 changes: 2 additions & 0 deletions src/config/default-app-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export class DefaultAppConfig implements AppConfig {
// In-memory cache of server-side rendered content
serverSide: {
debug: false,
// Link header is used for signposting functionality
headers: ['Link'],
// Cache specific to known bots. Allows you to serve cached contents to bots only.
// Defaults to caching 1,000 pages. Each page expires after 1 day
botCache: {
Expand Down
1 change: 1 addition & 0 deletions src/environments/environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const environment: BuildConfig = {
// In-memory cache of server-side rendered pages. Disabled in test environment (max=0)
serverSide: {
debug: false,
headers: ['Link'],
botCache: {
max: 0,
timeToLive: 24 * 60 * 60 * 1000, // 1 day
Expand Down

0 comments on commit 7ebdcd3

Please sign in to comment.