ソースを参照

feat(asset-server-plugin): Add configurable Cache-Control header (#2005)

Drayke 3 年 前
コミット
316d04da2f

+ 1 - 0
packages/asset-server-plugin/src/constants.ts

@@ -1 +1,2 @@
 export const loggerCtx = 'AssetServerPlugin';
+export const DEFAULT_CACHE_HEADER = 'public, max-age=15552000';

+ 17 - 1
packages/asset-server-plugin/src/plugin.ts

@@ -16,7 +16,7 @@ import fs from 'fs-extra';
 import path from 'path';
 
 import { getValidFormat } from './common';
-import { loggerCtx } from './constants';
+import { DEFAULT_CACHE_HEADER, loggerCtx } from './constants';
 import { defaultAssetStorageStrategyFactory } from './default-asset-storage-strategy-factory';
 import { HashedAssetNamingStrategy } from './hashed-asset-naming-strategy';
 import { SharpAssetPreviewStrategy } from './sharp-asset-preview-strategy';
@@ -151,6 +151,7 @@ export class AssetServerPlugin implements NestModule, OnApplicationBootstrap {
         { name: 'large', width: 800, height: 800, mode: 'resize' },
     ];
     private static options: AssetServerOptions;
+    private cacheHeader: string;
 
     /**
      * @description
@@ -196,6 +197,20 @@ export class AssetServerPlugin implements NestModule, OnApplicationBootstrap {
             }
         }
 
+        // Configure Cache-Control header
+        const { cacheHeader } = AssetServerPlugin.options;
+        if (!cacheHeader) {
+            this.cacheHeader = DEFAULT_CACHE_HEADER;
+        } else {
+            if (typeof cacheHeader === 'string') {
+                this.cacheHeader = cacheHeader;
+            } else {
+                this.cacheHeader = [cacheHeader.restriction, `max-age: ${cacheHeader.maxAge}`]
+                    .filter(value => !!value)
+                    .join(', ');
+            }
+        }
+
         const cachePath = path.join(AssetServerPlugin.options.assetUploadDir, this.cacheDir);
         fs.ensureDirSync(cachePath);
     }
@@ -232,6 +247,7 @@ export class AssetServerPlugin implements NestModule, OnApplicationBootstrap {
                 }
                 res.contentType(mimeType);
                 res.setHeader('content-security-policy', `default-src 'self'`);
+                res.setHeader('Cache-Control', this.cacheHeader);
                 res.send(file);
             } catch (e) {
                 const err = new Error('File not found');

+ 29 - 0
packages/asset-server-plugin/src/types.ts

@@ -43,6 +43,26 @@ export interface ImageTransformPreset {
     mode: ImageTransformMode;
 }
 
+/**
+ * @description
+ * A configuration option for the Cache-Control header in the AssetServerPlugin asset response.
+ *
+ * @docsCategory AssetServerPlugin
+ */
+export type CacheConfig = {
+    /**
+     * @description
+     * The max-age=N response directive indicates that the response remains fresh until N seconds after the response is generated.
+     */
+    maxAge: number;
+    /**
+     * @description
+     * The `private` response directive indicates that the response can be stored only in a private cache (e.g. local caches in browsers).
+     * The `public` response directive indicates that the response can be stored in a shared cache.
+     */
+    restriction?: 'public' | 'private';
+};
+
 /**
  * @description
  * The configuration options for the AssetServerPlugin.
@@ -117,4 +137,13 @@ export interface AssetServerOptions {
     storageStrategyFactory?: (
         options: AssetServerOptions,
     ) => AssetStorageStrategy | Promise<AssetStorageStrategy>;
+    /**
+     * @description
+     * Configures the `Cache-Control` directive for response to control caching in browsers and shared caches (e.g. Proxies, CDNs).
+     * Defaults to publicly cached for 6 months.
+     *
+     * @default 'public, max-age=15552000'
+     * @since 1.9.3
+     */
+    cacheHeader?: CacheConfig | string;
 }