mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Update SSR caching to only work when unauthenticated. Enhance config comments
This commit is contained in:
@@ -39,11 +39,16 @@ cache:
|
|||||||
maxBufferSize: 100
|
maxBufferSize: 100
|
||||||
timePerMethod:
|
timePerMethod:
|
||||||
PATCH: 3 # time in seconds
|
PATCH: 3 # time in seconds
|
||||||
# In-memory cache of server-side rendered content
|
# In-memory cache of server-side rendered pages. This cache stores the most recently accessed public pages.
|
||||||
|
# Pages are automatically added/dropped from this cache based on how recently they have been used.
|
||||||
serverSide:
|
serverSide:
|
||||||
# Maximum number of pages (rendered via SSR) to cache. Set to zero to disable server side caching.
|
# Maximum number of pages to cache. Set to zero (0) to disable server side caching. Default is 100, which means
|
||||||
|
# the 100 most recently accessed public pages will be cached. As all pages are cached in server memory,
|
||||||
|
# increasing this value will increase memory needs. Individual cached pages are usually small (<100KB),
|
||||||
|
# so max=100 should only require a maximum of 9-10MB of memory. Restarting the app clears this page cache.
|
||||||
max: 100
|
max: 100
|
||||||
# Amount of time after which cached pages are considered stale (in ms)
|
# Amount of time after which cached pages are considered stale (in ms). After becoming stale, the cached
|
||||||
|
# copy is automatically refreshed on the next request.
|
||||||
timeToLive: 900000 # 15 minutes
|
timeToLive: 900000 # 15 minutes
|
||||||
|
|
||||||
# Authentication settings
|
# Authentication settings
|
||||||
|
46
server.ts
46
server.ts
@@ -54,6 +54,8 @@ import { buildAppConfig } from './src/config/config.server';
|
|||||||
import { APP_CONFIG, AppConfig } from './src/config/app-config.interface';
|
import { APP_CONFIG, AppConfig } from './src/config/app-config.interface';
|
||||||
import { extendEnvironmentWithAppConfig } from './src/config/config.util';
|
import { extendEnvironmentWithAppConfig } from './src/config/config.util';
|
||||||
import { logStartupMessage } from './startup-message';
|
import { logStartupMessage } from './startup-message';
|
||||||
|
import { TOKENITEM } from 'src/app/core/auth/models/auth-token-info.model';
|
||||||
|
import { isAuthenticated } from 'src/app/core/auth/selectors';
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -113,13 +115,13 @@ export function app() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Add cookie parser middleware
|
* Add cookie parser middleware
|
||||||
* See [morgan](https://github.com/expressjs/cookie-parser)
|
* See [cookie-parser](https://github.com/expressjs/cookie-parser)
|
||||||
*/
|
*/
|
||||||
server.use(cookieParser());
|
server.use(cookieParser());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add parser for request bodies
|
* Add JSON parser for request bodies
|
||||||
* See [morgan](https://github.com/expressjs/body-parser)
|
* See [body-parser](https://github.com/expressjs/body-parser)
|
||||||
*/
|
*/
|
||||||
server.use(json());
|
server.use(json());
|
||||||
|
|
||||||
@@ -258,7 +260,7 @@ function serverSideRender(req, res, sendToUser: boolean = true) {
|
|||||||
if (hasNoValue(err) && hasValue(data)) {
|
if (hasNoValue(err) && hasValue(data)) {
|
||||||
res.locals.ssr = true; // mark response as SSR (enables text compression)
|
res.locals.ssr = true; // mark response as SSR (enables text compression)
|
||||||
// save server side rendered data to cache
|
// save server side rendered data to cache
|
||||||
saveToCache(getCacheKey(req), data);
|
saveToCache(req, data);
|
||||||
if (sendToUser) {
|
if (sendToUser) {
|
||||||
// send rendered page to user
|
// send rendered page to user
|
||||||
res.send(data);
|
res.send(data);
|
||||||
@@ -313,7 +315,7 @@ function addCacheControl(req, res, next) {
|
|||||||
*/
|
*/
|
||||||
function enableCache() {
|
function enableCache() {
|
||||||
if (cacheEnabled()) {
|
if (cacheEnabled()) {
|
||||||
// Initialize a new "least-recently-used" item cache.
|
// Initialize a new "least-recently-used" item cache (where least recently used items are removed first)
|
||||||
// See https://www.npmjs.com/package/lru-cache
|
// See https://www.npmjs.com/package/lru-cache
|
||||||
cache = new LRU( {
|
cache = new LRU( {
|
||||||
max: environment.cache.serverSide.max || 100, // 100 items in cache maximum
|
max: environment.cache.serverSide.max || 100, // 100 items in cache maximum
|
||||||
@@ -340,8 +342,10 @@ function cacheCheck(req, res, next) {
|
|||||||
let cacheHit = false;
|
let cacheHit = false;
|
||||||
let debug = false; // Enable to see cache hits & re-rendering logs
|
let debug = false; // Enable to see cache hits & re-rendering logs
|
||||||
|
|
||||||
// Only check cache if cache enabled & SSR is enabled
|
// Only check cache if cache enabled & NOT authenticated.
|
||||||
if (cacheEnabled()) {
|
// NOTE: Authenticated users cannot use the SSR cache. Cached pages only show data available to anonymous users.
|
||||||
|
// Only public pages can currently be cached, as the cached data is not user-specific.
|
||||||
|
if (cacheEnabled() && !isUserAuthenticated(req)) {
|
||||||
const key = getCacheKey(req);
|
const key = getCacheKey(req);
|
||||||
|
|
||||||
// Check if this page is in our cache
|
// Check if this page is in our cache
|
||||||
@@ -387,29 +391,25 @@ function getCacheKey(req): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save data to server side cache, if enabled. If caching is not enabled, this is a noop
|
* Save data to server side cache, if enabled. If caching is not enabled or user is authenticated, this is a noop
|
||||||
* @param key page key
|
* @param req current page request
|
||||||
* @param data page data to save to cache
|
* @param data page data to save to cache
|
||||||
*/
|
*/
|
||||||
function saveToCache(key: string, data: any) {
|
function saveToCache(req, data: any) {
|
||||||
// Only cache if caching is enabled and this path is allowed to be cached
|
// Only cache if caching is enabled and no one is currently authenticated. This means ONLY public pages can be cached.
|
||||||
if (cacheEnabled() && canCachePage(key)) {
|
// NOTE: It's not safe to save page data to the cache when a user is authenticated. In that situation,
|
||||||
cache.set(key, data);
|
// the page may include sensitive or user-specific materials. As the cache is shared across all users, it can only contain public info.
|
||||||
|
if (cacheEnabled() && !isUserAuthenticated(req)) {
|
||||||
|
cache.set(getCacheKey(req), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this path is allowed to be cached. Only public paths can be cached as the cache is shared across all users.
|
* Whether a user is authenticated or not
|
||||||
* @param key page key (corresponds to path of page)
|
|
||||||
* @returns true if allowed to be cached, false otherwise.
|
|
||||||
*/
|
*/
|
||||||
function canCachePage(key: string) {
|
function isUserAuthenticated(req): boolean {
|
||||||
// Only these publicly accessible pages can be cached.
|
// Check whether our authentication Cookie exists or not
|
||||||
// NOTE: Caching pages which require authentication is NOT ALLOWED. The same cache is used by all users & user-specific data must NEVER appear in cache.
|
return req.cookies[TOKENITEM];
|
||||||
const allowedPages = [/^\/$/, /^\/home$/, /^\/items\//, /^\/entities\//, /^\/collections\//, /^\/communities\//, /^\/search[\/?]?/, /\/browse\//, /^\/community-list$/];
|
|
||||||
|
|
||||||
// Check whether any of these regexs match with the passed in key
|
|
||||||
return allowedPages.some(regex => regex.test(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user